Files
fusion/packages/dashboard/app/components/command-center/__tests__/SystemStatsArea.test.tsx
gsxdsm 4df5c62854 FN-8133: add local codebase context metrics
Expose local codebase token estimates and apparent disk size in the project dashboard.

- Add a bounded, cached, symlink-safe codebase metrics service and project API.
- Display token and disk indicators across Command Center overview states.
- Add formatting, route, UI, and metric calibration coverage with a minor changeset.

Files changed:
 .changeset/fn-8133-codebase-metrics.md             |   7 +
 docs/dashboard-guide.md                            |   2 +-
 .../dashboard/app/__tests__/api-projects.test.ts   |  12 ++
 packages/dashboard/app/api/legacy.ts               |  14 ++
 .../components/command-center/CommandCenter.css    |   5 +
 .../components/command-center/CommandCenter.tsx    |  65 +++++++--
 .../CommandCenter.mobile-chart-layout.test.ts      |   4 +
 .../__tests__/CommandCenter.test.tsx               |  10 ++
 .../__tests__/SystemStatsArea.test.tsx             |   8 +
 .../command-center/areas/SystemStatsArea.tsx       |   8 +-
 .../app/utils/__tests__/formatBytes.test.ts        |  18 +++
 packages/dashboard/app/utils/formatBytes.ts        |  11 ++
 .../src/lib/__tests__/codebase-metrics.test.ts     |  62 ++++++++
 .../lib/__tests__/fixtures/token-corpus/README.md  |  17 +++
 .../fixtures/token-corpus/calibration/component.ts |   1 +
 .../fixtures/token-corpus/calibration/config.json  |   1 +
 .../lib/__tests__/fixtures/token-corpus/example.ts |   1 +
 .../lib/__tests__/fixtures/token-corpus/notes.md   |   3 +
 .../fixtures/token-corpus/reference-counts.json    |   9 ++
 .../__tests__/fixtures/token-corpus/settings.json  |   1 +
 .../lib/__tests__/fixtures/token-corpus/view.tsx   |   1 +
 packages/dashboard/src/lib/codebase-metrics.ts     | 161 +++++++++++++++++++++
 .../__tests__/codebase-metrics-route.test.ts       |  34 +++++
 .../src/routes/register-project-routes.ts          |  19 +++
 24 files changed, 456 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-8133

Fusion-Task-Lineage: d591636b-d4b8-469e-8788-c4516eeb8405

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 14:08:43 -07:00

407 lines
16 KiB
TypeScript

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react";
import "@testing-library/jest-dom";
import { SystemStatsArea } from "../areas/SystemStatsArea";
const mockFetchSystemStats = vi.fn();
const mockFetchNodeSystemStats = vi.fn();
const mockFetchGlobalSettings = vi.fn();
const mockFetchNodes = vi.fn();
const mockKillVitestProcesses = vi.fn();
const mockUpdateGlobalSettings = vi.fn();
vi.mock("../../../api", () => ({
fetchSystemStats: (...args: unknown[]) => mockFetchSystemStats(...args),
fetchNodeSystemStats: (...args: unknown[]) => mockFetchNodeSystemStats(...args),
fetchGlobalSettings: (...args: unknown[]) => mockFetchGlobalSettings(...args),
fetchNodes: (...args: unknown[]) => mockFetchNodes(...args),
killVitestProcesses: (...args: unknown[]) => mockKillVitestProcesses(...args),
updateGlobalSettings: (...args: unknown[]) => mockUpdateGlobalSettings(...args),
}));
const gb = 1024 * 1024 * 1024;
const mb = 1024 * 1024;
type NodeFixture = {
id: string;
name: string;
type: "local" | "remote";
status: "online";
maxConcurrent: number;
createdAt: string;
updatedAt: string;
};
type SystemStatsFixture = ReturnType<typeof baseStats>;
type SystemStatsFixtureOverrides = Partial<Omit<SystemStatsFixture, "systemStats" | "taskStats">> & {
systemStats?: Partial<SystemStatsFixture["systemStats"]>;
taskStats?: Partial<Omit<SystemStatsFixture["taskStats"], "agents">> & {
agents?: Partial<SystemStatsFixture["taskStats"]["agents"]>;
};
};
function sampleStats(overrides: SystemStatsFixtureOverrides = {}) {
return {
...baseStats(),
...overrides,
systemStats: {
...baseStats().systemStats,
...overrides.systemStats,
},
taskStats: {
...baseStats().taskStats,
...overrides.taskStats,
agents: {
...baseStats().taskStats.agents,
...overrides.taskStats?.agents,
},
},
};
}
function nodeFixture(id: string, name: string, type: "local" | "remote"): NodeFixture {
return { id, name, type, status: "online", maxConcurrent: 1, createdAt: "", updatedAt: "" };
}
function baseStats() {
return {
systemStats: {
rss: 5 * gb,
heapUsed: 900 * mb,
heapTotal: 1200 * mb,
heapLimit: 1000 * mb,
external: 50 * mb,
arrayBuffers: 20 * mb,
cpuPercent: 68.4,
loadAvg: [1.2, 0.8, 0.5] as [number, number, number],
cpuCount: 8,
systemTotalMem: 10 * gb,
systemFreeMem: 1 * gb,
pid: 12345,
nodeVersion: "v22.0.0",
platform: "darwin/arm64",
},
taskStats: {
total: 6,
byColumn: {
triage: 1,
todo: 2,
"in-progress": 1,
"in-review": 1,
done: 1,
},
active: 2,
agents: {
idle: 1,
active: 2,
running: 0,
error: 1,
},
},
vitestProcessCount: 2,
vitestLastAutoKillAt: "2026-04-27T12:00:00.000Z",
};
}
describe("SystemStatsArea", () => {
beforeEach(() => {
vi.clearAllMocks();
mockFetchSystemStats.mockResolvedValue(sampleStats());
mockFetchNodeSystemStats.mockResolvedValue(sampleStats());
mockFetchGlobalSettings.mockResolvedValue({ vitestAutoKillEnabled: true, vitestKillThresholdPct: 90 });
mockFetchNodes.mockResolvedValue([]);
mockKillVitestProcesses.mockResolvedValue({ killed: 2, pids: [111, 222] });
mockUpdateGlobalSettings.mockResolvedValue({});
});
afterEach(() => {
vi.useRealTimers();
});
it("renders gauges, trends, bars, details, and Vitest controls for populated stats", async () => {
render(<SystemStatsArea projectId="proj-1" />);
await waitFor(() => {
expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-1");
expect(mockFetchGlobalSettings).toHaveBeenCalledTimes(1);
});
expect(await screen.findByTestId("cc-area-system")).toBeInTheDocument();
expect(screen.getByTestId("cc-system-cpu-gauge")).toHaveTextContent("68%");
expect(screen.getByTestId("cc-system-mem-gauge")).toHaveTextContent("90%");
expect(screen.getByTestId("cc-system-heap-gauge")).toHaveTextContent("90%");
expect(screen.getByTestId("cc-system-cpu-trend")).toBeInTheDocument();
expect(screen.getByTestId("cc-system-memory-trend")).toBeInTheDocument();
expect(screen.getByTestId("cc-system-line")).toBeInTheDocument();
expect(screen.getByRole("img", { name: "Resource trend" })).toBeInTheDocument();
expect(screen.getByTestId("cc-system-pie")).toBeInTheDocument();
expect(screen.getByRole("img", { name: "Task distribution" })).toBeInTheDocument();
expect(screen.getByTestId("cc-system-tasks-bar")).toHaveTextContent("in-progress");
expect(screen.getByTestId("cc-system-agents-bar")).toHaveTextContent("active");
expect(screen.getByTestId("cc-system-details-grid")).toHaveTextContent("RSS");
expect(screen.getByTestId("cc-system-details-grid")).toHaveTextContent("5.00 GB");
expect(screen.getByTestId("cc-system-vitest-controls")).toHaveTextContent("Vitest Processes");
});
it("renders granular sub-megabyte system measurements", async () => {
mockFetchSystemStats.mockResolvedValue(sampleStats({ systemStats: { external: 512 } }));
render(<SystemStatsArea />);
expect(await screen.findByTestId("cc-system-details-grid")).toHaveTextContent("512 B");
});
it("renders the first-sample CPU state safely without NaN", async () => {
mockFetchSystemStats.mockResolvedValue(sampleStats({ systemStats: { cpuPercent: null } }));
render(<SystemStatsArea />);
await screen.findByTestId("cc-area-system");
expect(screen.getByTestId("cc-system-cpu-gauge")).toHaveTextContent("—");
expect(screen.getByTestId("cc-system-cpu-gauge")).toHaveTextContent("Sampling");
expect(screen.getByTestId("cc-system-line")).toBeInTheDocument();
expect(screen.getByTestId("cc-area-system")).not.toHaveTextContent("NaN");
});
it("renders zero-value task and agent bars when collections are empty", async () => {
mockFetchSystemStats.mockResolvedValue(sampleStats({
taskStats: {
total: 0,
byColumn: {},
active: 0,
agents: { idle: 0, active: 0, running: 0, error: 0 },
},
}));
render(<SystemStatsArea />);
await screen.findByTestId("cc-area-system");
const taskBars = screen.getByTestId("cc-system-tasks-bar");
const agentBars = screen.getByTestId("cc-system-agents-bar");
expect(within(taskBars).getByText("triage")).toBeInTheDocument();
expect(within(agentBars).getByText("idle")).toBeInTheDocument();
expect(within(taskBars).getAllByText("0").length).toBeGreaterThan(0);
expect(within(agentBars).getAllByText("0").length).toBeGreaterThan(0);
expect(screen.queryByTestId("cc-system-pie")).toBeNull();
expect(screen.getByTestId("cc-system-line")).toBeInTheDocument();
expect(screen.getByTestId("cc-area-system")).not.toHaveTextContent("NaN");
});
it("keeps the last stats visible when a later poll fails", async () => {
vi.useFakeTimers();
mockFetchSystemStats.mockResolvedValueOnce(sampleStats()).mockRejectedValueOnce(new Error("poll failed"));
render(<SystemStatsArea />);
await act(async () => {
await Promise.resolve();
});
expect(screen.getByTestId("cc-area-system")).toBeInTheDocument();
await act(async () => {
vi.advanceTimersByTime(5_000);
await Promise.resolve();
});
expect(screen.getByTestId("cc-area-system")).toHaveTextContent("Latest refresh failed: poll failed");
expect(screen.getByTestId("cc-system-details-grid")).toHaveTextContent("RSS");
});
it("shows the initial error state when the first fetch fails", async () => {
mockFetchSystemStats.mockRejectedValue(new Error("initial failure"));
render(<SystemStatsArea />);
expect(await screen.findByTestId("cc-area-system-error")).toHaveTextContent("initial failure");
expect(screen.queryByTestId("cc-system-pie")).toBeNull();
expect(screen.queryByTestId("cc-system-line")).toBeNull();
});
it("confirms before killing Vitest and persists settings changes", async () => {
render(<SystemStatsArea projectId="proj-1" />);
await screen.findByTestId("cc-area-system");
const killButton = screen.getByTestId("cc-system-kill-vitest");
fireEvent.click(killButton);
expect(killButton).toHaveTextContent("Confirm Kill?");
fireEvent.click(killButton);
await waitFor(() => {
expect(mockKillVitestProcesses).toHaveBeenCalledWith("proj-1");
});
expect(await screen.findByText("Killed 2 processes")).toBeInTheDocument();
fireEvent.click(screen.getByLabelText("Auto-kill vitest on memory pressure"));
await waitFor(() => {
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith({ vitestAutoKillEnabled: false });
});
fireEvent.change(screen.getByLabelText("Kill threshold (%)"), { target: { value: "120" } });
await waitFor(() => {
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith({ vitestKillThresholdPct: 99 });
});
});
it("renders a node selector with local and remote nodes", async () => {
mockFetchNodes.mockResolvedValue([
nodeFixture("local-node", "Local", "local"),
nodeFixture("remote-a", "Remote A", "remote"),
nodeFixture("remote-b", "Remote B", "remote"),
]);
render(<SystemStatsArea projectId="proj-1" />);
const selector = await screen.findByTestId("cc-system-node-select");
expect(selector).toHaveAccessibleName("Select system stats node");
expect(within(selector).getByRole("option", { name: "Local (this node)" })).toBeInTheDocument();
expect(within(selector).getByRole("option", { name: "Remote A" })).toBeInTheDocument();
expect(within(selector).getByRole("option", { name: "Remote B" })).toBeInTheDocument();
expect(screen.getByText("Viewing Local")).toBeInTheDocument();
});
it("routes remote stats and Vitest kills with the selected node id while local calls stay local", async () => {
mockFetchNodes.mockResolvedValue([
nodeFixture("local-node", "Local", "local"),
nodeFixture("remote-a", "Remote A", "remote"),
]);
render(<SystemStatsArea projectId="proj-1" />);
const selector = await screen.findByTestId("cc-system-node-select");
await waitFor(() => {
expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-1");
});
expect(mockFetchSystemStats).not.toHaveBeenCalledWith("proj-1", "local-node", "local-node");
mockFetchSystemStats.mockClear();
fireEvent.change(selector, { target: { value: "remote-a" } });
await waitFor(() => {
expect(mockFetchNodeSystemStats).toHaveBeenCalledWith("remote-a", "proj-1");
});
expect(mockFetchSystemStats).not.toHaveBeenCalledWith("proj-1", "remote-a", "local-node");
expect(screen.getByText("Viewing Remote A")).toBeInTheDocument();
const killButton = screen.getByTestId("cc-system-kill-vitest");
fireEvent.click(killButton);
fireEvent.click(killButton);
await waitFor(() => {
expect(mockKillVitestProcesses).toHaveBeenCalledWith("proj-1", "remote-a", "local-node");
});
});
it("shows a remote fetch error while keeping the node selector usable", async () => {
mockFetchNodes.mockResolvedValue([
nodeFixture("local-node", "Local", "local"),
nodeFixture("remote-a", "Remote A", "remote"),
]);
mockFetchNodeSystemStats.mockRejectedValueOnce(new Error("remote offline"));
render(<SystemStatsArea projectId="proj-1" />);
const selector = await screen.findByTestId("cc-system-node-select");
await waitFor(() => expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-1"));
fireEvent.change(selector, { target: { value: "remote-a" } });
expect(await screen.findByText("Latest refresh failed: remote offline")).toBeInTheDocument();
expect(screen.getByTestId("cc-system-node-select")).toBeInTheDocument();
mockFetchSystemStats.mockClear();
fireEvent.change(selector, { target: { value: "local-node" } });
await waitFor(() => expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-1"));
});
it("resets the rolling sample buffer and re-fetches when switching nodes", async () => {
mockFetchNodes.mockResolvedValue([
nodeFixture("local-node", "Local", "local"),
nodeFixture("remote-a", "Remote A", "remote"),
]);
mockFetchSystemStats
.mockResolvedValueOnce(sampleStats({ systemStats: { cpuPercent: 10, systemFreeMem: 9 * gb, heapUsed: 100 * mb } }))
.mockResolvedValueOnce(sampleStats({ systemStats: { cpuPercent: 20, systemFreeMem: 8 * gb, heapUsed: 200 * mb } }))
.mockResolvedValue(sampleStats({ systemStats: { cpuPercent: 30, systemFreeMem: 7 * gb, heapUsed: 300 * mb } }));
mockFetchNodeSystemStats.mockResolvedValue(sampleStats({ systemStats: { cpuPercent: 70, systemFreeMem: 3 * gb, heapUsed: 700 * mb } }));
const { container } = render(<SystemStatsArea projectId="proj-1" />);
const selector = await screen.findByTestId("cc-system-node-select");
await waitFor(() => {
expect(container.querySelectorAll("[data-testid='cc-system-cpu-trend'] .cc-sparkline-bar").length).toBeGreaterThan(0);
});
fireEvent.change(selector, { target: { value: "remote-a" } });
await waitFor(() => {
expect(mockFetchNodeSystemStats).toHaveBeenCalledWith("remote-a", "proj-1");
expect(container.querySelectorAll("[data-testid='cc-system-cpu-trend'] .cc-sparkline-bar")).toHaveLength(1);
});
});
it("hides the node selector for local-only, empty, and failed node lists while telemetry still loads", async () => {
mockFetchNodes.mockResolvedValueOnce([nodeFixture("local-node", "Local", "local")]);
const { unmount } = render(<SystemStatsArea projectId="proj-1" />);
await screen.findByTestId("cc-area-system");
await waitFor(() => expect(mockFetchNodes).toHaveBeenCalledTimes(1));
expect(screen.queryByTestId("cc-system-node-select")).toBeNull();
expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-1");
unmount();
vi.clearAllMocks();
mockFetchSystemStats.mockResolvedValue(sampleStats());
mockFetchNodeSystemStats.mockResolvedValue(sampleStats());
mockFetchGlobalSettings.mockResolvedValue({ vitestAutoKillEnabled: true, vitestKillThresholdPct: 90 });
mockFetchNodes.mockResolvedValueOnce([]);
const { unmount: unmountEmpty } = render(<SystemStatsArea projectId="proj-1" />);
await screen.findByTestId("cc-area-system");
await waitFor(() => expect(mockFetchNodes).toHaveBeenCalledTimes(1));
expect(screen.queryByTestId("cc-system-node-select")).toBeNull();
expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-1");
unmountEmpty();
vi.clearAllMocks();
mockFetchSystemStats.mockResolvedValue(sampleStats());
mockFetchNodeSystemStats.mockResolvedValue(sampleStats());
mockFetchGlobalSettings.mockResolvedValue({ vitestAutoKillEnabled: true, vitestKillThresholdPct: 90 });
mockFetchNodes.mockRejectedValueOnce(new Error("nodes unavailable"));
render(<SystemStatsArea projectId="proj-2" />);
await screen.findByTestId("cc-area-system");
await waitFor(() => expect(mockFetchNodes).toHaveBeenCalledTimes(1));
expect(screen.queryByTestId("cc-system-node-select")).toBeNull();
expect(mockFetchSystemStats).toHaveBeenCalledWith("proj-2");
});
it("keeps the node selector inside the mobile System-area layout contract", () => {
const css = readFileSync(join(process.cwd(), "app/components/command-center/areas/SystemStatsArea.css"), "utf8");
expect(css).toContain("@media (max-width: 768px)");
expect(css).toContain(".cc-system-node-selector");
expect(css).toContain("inline-size: 100%");
});
it("polls every five seconds and clears the interval on unmount", async () => {
vi.useFakeTimers();
const { unmount } = render(<SystemStatsArea />);
await act(async () => {
await Promise.resolve();
});
expect(screen.getByTestId("cc-area-system")).toBeInTheDocument();
expect(mockFetchSystemStats).toHaveBeenCalledTimes(1);
await act(async () => {
vi.advanceTimersByTime(5_000);
await Promise.resolve();
});
expect(mockFetchSystemStats).toHaveBeenCalledTimes(2);
unmount();
await act(async () => {
vi.advanceTimersByTime(5_000);
await Promise.resolve();
});
expect(mockFetchSystemStats).toHaveBeenCalledTimes(2);
});
});