/** * Memory pressure thresholds. * * Steve 2026-05-15 dogfood: macOS keeps the "memory used %" stat at * 95-99% on virtually every Mac because the OS aggressively uses RAM * for file cache (which is reclaimable on demand). Gating spawns purely * on usedPercent meant the user's machine permanently skipped every * wake action — agents could never come back online. Concrete signal * from the log: `consecutiveSkips` climbing past 450 with freeMB * fluctuating 80-800 (i.e. plenty of real headroom most of the time). * * The fix: keep the percent check as a soft signal, but only DECLARE * memory pressure when freeMB drops below an absolute headroom floor. * A fresh Claude Code process is ~150-200MB RSS; reserve 300MB so we * never spawn into an actual OOM situation while letting the cache- * inflated 95-99% percent reading pass. * * Steve 2026-05-22 dogfood follow-up: even with the 300MB floor, the * gate fires constantly on macOS because `os.freemem()` only counts * STRICTLY-FREE pages — it excludes inactive + speculative pages that * the kernel can reclaim on demand. On a typical Mac with 3GB+ of * reclaimable cache, os.freemem() routinely reports 50-200MB while * Activity Monitor / `vm_stat` show 3-4GB available. The reconciler * was effectively never letting wakes through. * * Real fix: on macOS use `vm_stat` to compute AVAILABLE memory * (free + inactive + speculative), which is what the kernel itself * uses for OOM decisions. Linux's `os.freemem()` is accurate and * keeps the old path. */ export declare const MEMORY_PRESSURE_SPAWN_THRESHOLD = 90; export declare const MEMORY_PRESSURE_MIN_FREE_MB = 300; /** * Get the platform-appropriate free-memory reading in bytes. * * Exposed for tests; production callers should use {@link getMemoryStats} * or {@link isUnderMemoryPressure} instead. * * @returns free memory in bytes; falls back to os.freemem() if the * macOS vm_stat parse fails. */ export declare function getAvailableMemoryBytes(): number; /** * Check if the system is under memory pressure. * * Returns true only when BOTH: * - usedPercent >= MEMORY_PRESSURE_SPAWN_THRESHOLD (90%), AND * - freeMB < MEMORY_PRESSURE_MIN_FREE_MB (300MB) * * On macOS, "free" includes reclaimable inactive+speculative pages * (parsed from `vm_stat`) — without this the reading is ~50MB on a * Mac that actually has gigabytes of headroom, and the gate would * fire constantly. See module-doc comment for the dogfood history. * * @returns true if system should NOT spawn new processes */ export declare function isUnderMemoryPressure(): boolean; /** * Get current memory usage stats. * @returns Object with totalMB, freeMB, usedPercent */ export declare function getMemoryStats(): { totalMB: number; freeMB: number; usedPercent: number; swapUsedPercent?: number; pressureElevated?: boolean; }; /** * Swap use and the kernel's own pressure verdict. * * "Available" memory counts inactive pages as free, which on macOS stays * in the gigabytes even while the machine is swapping itself to a crawl * (2026-09-23: 10.7 of 12 GB swap, 7 GB compressed, load 117 — and the * idle-stop gate still read "memory is fine"). Swap fill and * `kern.memorystatus_vm_pressure_level` (1 normal, 2 warn, 4 critical) * see that; on Linux, SwapTotal/SwapFree from /proc/meminfo. * * @returns Swap share in use and whether the OS reports pressure, or null if unreadable */ export declare function readSwapPressure(): { swapUsedPercent: number; pressureElevated: boolean; } | null; /** Reset the swap reading cache — test affordance. */ export declare function _resetSwapCacheForTesting(): void; /** Reset the vm_stat cache — test affordance. */ export declare function _resetVmStatCacheForTesting(): void; //# sourceMappingURL=system-health.util.d.ts.map