refactor(tui): /clean pass on memory + resize helpers

KISS/DRY sweep — drops ~90 LOC with no behavior change.

- circularBuffer: drop unused pushAll/toArray/size; fold toArray into drain
- gracefulExit: inline Cleanup type + failsafe const; signal→code as a
  record instead of nested ternary; drop dead .catch on Promise.allSettled;
  drop unused forceExit
- memory: inline heapDumpRoot() + writeSnapshot() (single-use); collapse
  the two fd/smaps try/catch blocks behind one `swallow` helper; build
  potentialLeaks functionally (array+filter) instead of imperative
  push-chain; UNITS at file bottom
- memoryMonitor: inline DEFAULTS; drop unused onSnapshot; collapse
  dumpedHigh/dumpedCritical bools to a single Set; single callback
  dispatch line instead of duplicated if-chains
- entry.tsx: factor `dumpNotice` formatter (used twice by onHigh +
  onCritical)
- useMainApp resize debounce: drop redundant `if (timer)` guards
  (clearTimeout(undefined) is a no-op); init as undefined not null
- useVirtualHistory: trim wall-of-text comment to one-line intent; hoist
  `const n = items.length`; split comma-declared lets; remove the
  `;[start, end] = frozenRange` destructure in favor of direct Math.min
  clamps; hoist `hi` init in upperBound for consistency

Validation: tsc clean (both configs), eslint clean on touched files,
vitest 102/102, build produces shebang-preserved dist/entry.js,
performHeapDump smoke-test still writes valid snapshot + diagnostics.
This commit is contained in:
Brooklyn Nicholson 2026-04-20 18:51:12 -05:00
parent 0078f743e6
commit 82b927777c
7 changed files with 89 additions and 182 deletions

View file

@ -14,57 +14,37 @@ export interface MemoryMonitorOptions {
intervalMs?: number
onCritical?: (snap: MemorySnapshot, dump: HeapDumpResult | null) => void
onHigh?: (snap: MemorySnapshot, dump: HeapDumpResult | null) => void
onSnapshot?: (snap: MemorySnapshot) => void
}
const GB = 1024 ** 3
const DEFAULTS = {
criticalBytes: 2.5 * GB,
highBytes: 1.5 * GB,
intervalMs: 10_000
}
export function startMemoryMonitor({
criticalBytes = DEFAULTS.criticalBytes,
highBytes = DEFAULTS.highBytes,
intervalMs = DEFAULTS.intervalMs,
criticalBytes = 2.5 * GB,
highBytes = 1.5 * GB,
intervalMs = 10_000,
onCritical,
onHigh,
onSnapshot
onHigh
}: MemoryMonitorOptions = {}): () => void {
let dumpedHigh = false
let dumpedCritical = false
const dumped = new Set<Exclude<MemoryLevel, 'normal'>>()
const tick = async () => {
const { heapUsed, rss } = process.memoryUsage()
const level: MemoryLevel = heapUsed >= criticalBytes ? 'critical' : heapUsed >= highBytes ? 'high' : 'normal'
const snap: MemorySnapshot = { heapUsed, level, rss }
onSnapshot?.(snap)
if (level === 'normal') {
dumpedHigh = false
dumpedCritical = false
return void dumped.clear()
}
if (dumped.has(level)) {
return
}
if (level === 'high' && !dumpedHigh) {
dumpedHigh = true
const dump = await performHeapDump('auto-high').catch(() => null)
dumped.add(level)
const dump = await performHeapDump(level === 'critical' ? 'auto-critical' : 'auto-high').catch(() => null)
onHigh?.(snap, dump)
const snap: MemorySnapshot = { heapUsed, level, rss }
return
}
if (level === 'critical' && !dumpedCritical) {
dumpedCritical = true
const dump = await performHeapDump('auto-critical').catch(() => null)
onCritical?.(snap, dump)
}
;(level === 'critical' ? onCritical : onHigh)?.(snap, dump)
}
const handle = setInterval(() => void tick(), intervalMs)