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
33 lines
1.3 KiB
TypeScript
33 lines
1.3 KiB
TypeScript
import * as os from "node:os";
|
||
|
||
export interface AvailableMemoryReading {
|
||
bytes: number;
|
||
/** False when only `os.freemem()` was available — unusable as a pressure signal. */
|
||
reliable: boolean;
|
||
}
|
||
|
||
/**
|
||
* FNXC:SystemMetrics 2026-06-21-13:01:
|
||
* macOS `os.freemem()` only counts truly-free pages and excludes inactive/cached pages that the OS can reclaim on demand, so total-minus-freemem over-reports memory used and can make an idle Mac look ~95–99% full.
|
||
* Prefer Node's `process.availableMemory()` because it reports OS-available memory and matches user-facing tools such as Activity Monitor. Keep the `os.freemem()` fallback for runtimes without the API, but flag it unreliable so pressure-sensitive callers can refuse to act on a garbage ratio.
|
||
*/
|
||
export function getAvailableMemoryInfo(): AvailableMemoryReading {
|
||
const processFn = (process as unknown as { availableMemory?: () => number }).availableMemory;
|
||
if (typeof processFn === "function") {
|
||
try {
|
||
const value = processFn.call(process);
|
||
if (Number.isFinite(value) && value > 0) {
|
||
return { bytes: value, reliable: true };
|
||
}
|
||
} catch {
|
||
// Fall through to the compatibility path below.
|
||
}
|
||
}
|
||
|
||
return { bytes: os.freemem(), reliable: false };
|
||
}
|
||
|
||
export function getAvailableMemoryBytes(): number {
|
||
return getAvailableMemoryInfo().bytes;
|
||
}
|