85 lines · 3.1 KB · TypeScript
RawDownload
import { readFileSync } from "node:fs";import { arch, cpus, freemem, platform, release, totalmem, uptime } from "node:os";import { Effect } from "effect";import type { HostArch, HostInfo, HostPlatform } from "../contracts";import { realProcessRunner } from "../../../core/command";import { neverFails, type DeviceProbe } from "./probe"; export const hostPlatform = (): HostPlatform => {  const current = platform();  if (current === "darwin" || current === "win32") return current;  return "linux";}; export const hostArch = (): HostArch => (arch() === "arm64" ? "arm64" : "x64"); /** * `os.freemem()` counts only wholly unused pages, so on Linux it understates what is * actually available by the size of the page cache. MemAvailable is the kernel's own * estimate and is the number a launch decision should use. */const linuxMemoryField = (field: string): number | null => {  try {    const meminfo = readFileSync("/proc/meminfo", "utf8");    const match = new RegExp(`^${field}:\\s+(\\d+)\\s+kB`, "m").exec(meminfo);    const kilobytes = match?.[1];    return kilobytes === undefined ? null : Number(kilobytes) * 1024;  } catch {    return null;  }}; /** * macOS reports almost everything as "inactive" rather than free, so `os.freemem()` on a * 34 GB Mac routinely answers a few hundred MB. Inactive and speculative pages are * reclaimable on demand, so the honest available figure is free + inactive + speculative, * minus whatever is pinned by compression. */const darwinAvailableBytes = (): number | null => {  const result = realProcessRunner.runSync("vm_stat", [], { timeoutMs: 2_000 });  if (result.status !== 0 || result.stdout.length === 0) return null;  const pageSize = Number(/page size of (\d+) bytes/.exec(result.stdout)?.[1] ?? 16384);  const pages = (label: string): number =>    Number(new RegExp(`${label}:\\s+(\\d+)`).exec(result.stdout)?.[1] ?? 0);  const reclaimable =    pages("Pages free") + pages("Pages inactive") + pages("Pages speculative") + pages("Pages purgeable");  const bytes = reclaimable * pageSize;  return Number.isFinite(bytes) && bytes > 0 ? bytes : null;}; const availableMemoryBytes = (): number => {  const platformName = hostPlatform();  if (platformName === "linux") return linuxMemoryField("MemAvailable") ?? freemem();  if (platformName === "darwin") return darwinAvailableBytes() ?? freemem();  return freemem();}; const swapTotalBytes = (): number | null =>  hostPlatform() === "linux" ? linuxMemoryField("SwapTotal") : null; export const readHostInfo = (): HostInfo => {  const processors = cpus();  return {    cpuModel: processors[0]?.model.trim() ?? "unknown",    cpuCount: processors.length,    memoryTotalBytes: totalmem(),    memoryAvailableBytes: availableMemoryBytes(),    swapTotalBytes: swapTotalBytes(),    platform: hostPlatform(),    arch: hostArch(),    release: release(),    uptimeSeconds: Math.round(uptime()),  };}; export const hostProbe: DeviceProbe = {  id: "host",  detect: () => true,  run: () =>    neverFails(      Effect.sync(() => ({        fragment: { host: readHostInfo() },        capabilities: ["hostMemory" as const],      })),    ),};