/** * Pre-render memory estimate. * * The render pipeline materializes every `` into an array of * length `count` before the main loop starts. Some terminals also * materialize the rendered text into one large string (`toString()`), * while streaming terminals (`toIterator()`, `toStream()`, `writeFile()`, * CLI output) do not. * * This module computes a rough estimate of how many bytes the run will * need and compares it against the machine's TOTAL physical RAM. We gate * on total — not the OS's instantaneous "free" number — on purpose: modern * operating systems (macOS especially) keep RAM busy with reclaimable * caches and compressed pages, and hand it back the moment a process asks. * `os.freemem()` therefore under-reports usable memory by many times (on a * 32 GB Mac it can read <1 GB while ~13 GB is instantly reclaimable), which * would wrongly abort perfectly runnable jobs. What actually bounds a run is * how much fits in physical RAM before it thrashes — i.e. total memory. * * If the estimate is a large fraction of total RAM, we emit a *warning* * (the run may be slow / lean on swap but is allowed to proceed); only when * it can't plausibly fit at all do we escalate to an *error*. * * The estimate is deliberately rough: JavaScript string memory layout * depends on the engine, garbage-collector overhead is unknown, and * output size depends on the DSL template. We use wide safety margins * and err on the side of over-reporting. */ import type { Diagnostic } from './diagnostic.js'; export interface MemoryEstimate { /** Estimated peak bytes the run will need. */ readonly estimatedBytes: number; /** Estimated bytes held by materialized sequence arrays. */ readonly sequenceBytes?: number; /** Estimated bytes held by the complete rendered output string, if included. */ readonly renderedOutputBytes?: number; /** Whether the estimate includes a complete rendered output string. */ readonly includesRenderedOutput?: boolean; /** Total physical RAM of the machine — the real ceiling a run competes for. */ readonly totalBytes: number; /** * Free RAM reported by the OS at estimation time. Kept for context in the * message only; it does NOT drive the warn/error decision (see module doc: * `freemem()` under-reports usable memory because the OS reclaims caches on * demand). May be absent when only a total-based ratio was supplied. */ readonly freeBytes?: number; /** Fraction of TOTAL RAM the estimate represents (0 to 1+). */ readonly ratio: number; } export interface MemoryEstimateOptions { /** * `materialized` includes the complete rendered output string, matching * `TDC.toString()`. `streaming` excludes it, matching `toIterator()`, * `toStream()`, `writeFile()`, and the CLI. */ readonly output?: 'materialized' | 'streaming'; /** * `memory` (Engine 1, default) materializes each sequence into an array of * length `count`, so registry memory scales with `count`. `stream` * (Engine 2, `mode="stream"` / `--stream`) computes each value lazily per * row, so registry memory is O(number of sequence slots) — independent of * `count`. A large `count` under Engine 2 is NOT a memory risk. */ readonly engine?: 'memory' | 'stream'; } /** * Compute a rough memory estimate for a planned render and, if the * estimate is alarming, return a diagnostic warning. `sequencesCount` * includes built-ins (`_count`, `_first`, `_last`, `_total`) plus every * `` declared in ``. For compound sequences, count each * *field* as a separate sequence — that's what the registry stores. */ export declare function estimateMemoryUsage(cardCount: number, sequencesCount: number, options?: MemoryEstimateOptions): MemoryEstimate; /** * Produce a diagnostic warning when the estimate looks risky. Returns * `undefined` when the estimate is comfortably within safe bounds. */ export declare function memoryWarning(estimate: MemoryEstimate): Diagnostic | undefined; //# sourceMappingURL=memory-estimate.d.ts.map