Files
fusion/packages/core/src/system-metrics.ts
gsxdsm d99246cb74 FN-6834: use OS-available memory for system metrics
Use shared OS-available memory readings so macOS cache/inactive pages are not counted as used.

- Add a core available-memory helper that prefers `process.availableMemory()` and flags `freemem` fallback reliability.
- Route core metrics, dashboard system stats, and the dashboard TUI through the shared helper.
- Move and expand memory tests across core, dashboard routes, and verification coverage while documenting the telemetry behavior.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/fix-macos-memory-used.md                |  5 ++
 docs/architecture.md                               |  2 +-
 docs/dashboard-guide.md                            |  2 +-
 .../__tests__/available-memory.test.ts             | 54 --------------
 .../cli/src/commands/dashboard-tui/controller.ts   | 37 +---------
 .../core/src/__tests__/available-memory.test.ts    | 83 ++++++++++++++++++++++
 packages/core/src/__tests__/system-metrics.test.ts | 36 +++++++++-
 packages/core/src/available-memory.ts              | 32 +++++++++
 packages/core/src/index.ts                         |  1 +
 packages/core/src/system-metrics.ts                |  9 ++-
 .../dashboard/src/__tests__/routes-system.test.ts  | 27 +++++++
 packages/dashboard/src/routes.ts                   |  7 +-
 .../src/__tests__/run-verification-command.test.ts | 18 +++++
 13 files changed, 218 insertions(+), 95 deletions(-)

Fusion-Task-Id: FN-6834

Fusion-Task-Lineage: 2e651551-6c35-46d1-b517-535758c7ace2
2026-06-21 13:32:19 -07:00

69 lines
2.1 KiB
TypeScript

import { cpus, totalmem, uptime as getUptime } from "node:os";
import * as checkDiskSpaceModule from "check-disk-space";
import { getAvailableMemoryBytes } from "./available-memory.js";
import type { SystemMetrics } from "./types.js";
const checkDiskSpace = ((checkDiskSpaceModule as { default?: unknown }).default ??
checkDiskSpaceModule) as (directoryPath: string) => Promise<{
diskPath: string;
free: number;
size: number;
}>;
function clamp(value: number, min: number, max: number): number {
if (!Number.isFinite(value)) return min;
return Math.min(max, Math.max(min, value));
}
function toNonNegative(value: number): number {
if (!Number.isFinite(value) || value < 0) {
return 0;
}
return value;
}
/**
* Collect host-level system metrics for mesh state reporting.
*/
export async function collectSystemMetrics(dbPath?: string): Promise<SystemMetrics> {
const cpuTimes = cpus();
let busyTime = 0;
let totalTime = 0;
for (const cpu of cpuTimes) {
const busy = cpu.times.user + cpu.times.nice + cpu.times.sys;
const total = busy + cpu.times.idle + cpu.times.irq;
busyTime += busy;
totalTime += total;
}
const cpuUsage = totalTime > 0 ? (busyTime / totalTime) * 100 : 0;
const memoryTotal = toNonNegative(totalmem());
/*
FNXC:SystemMetrics 2026-06-21-13:01:
Mesh metrics must compute used memory from OS-available memory instead of raw `freemem()` so macOS inactive/cache pages are not incorrectly reported as used.
*/
const rawMemoryUsed = memoryTotal - toNonNegative(getAvailableMemoryBytes());
const memoryUsed = clamp(rawMemoryUsed, 0, memoryTotal);
const diskPath = dbPath ?? process.cwd();
const diskSpace = await checkDiskSpace(diskPath);
const storageTotal = toNonNegative(diskSpace.size);
const rawStorageUsed = storageTotal - toNonNegative(diskSpace.free);
const storageUsed = clamp(rawStorageUsed, 0, storageTotal);
const uptime = toNonNegative(getUptime() * 1000);
return {
cpuUsage: clamp(cpuUsage, 0, 100),
memoryUsed,
memoryTotal,
storageUsed,
storageTotal,
uptime,
reportedAt: new Date().toISOString(),
};
}