import { app, BrowserWindow, webContents } from 'electron'; import { monitorEventLoopDelay } from 'node:perf_hooks'; export type PerformanceSnapshot = { capturedAt: number; eventLoopDelayMs: number; gpu: ReturnType; processes: Array<{ pid: number; type: string; cpuPercent: number; workingSetSize: number; }>; windows: number; webContents: number; background: { activity: { visible: boolean; module: string | null }; leaseCount: number; }; }; type LifecycleDiagnostics = { getActivity(): { visible: boolean; module: string | null }; getLeaseCount(): number; }; // Keep the sampler alive for the process lifetime, but only expose aggregate // histogram values. No request payloads, URLs or project data enter this // diagnostic path. const eventLoopMonitor = monitorEventLoopDelay({ resolution: 20 }); eventLoopMonitor.enable(); export function collectPerformanceSnapshot(lifecycle?: LifecycleDiagnostics): PerformanceSnapshot { const eventLoopDelayMs = eventLoopMonitor.max / 1e6; eventLoopMonitor.reset(); return { capturedAt: Date.now(), eventLoopDelayMs: Math.round(eventLoopDelayMs * 100) / 100, gpu: app.getGPUFeatureStatus(), processes: app.getAppMetrics().map((metric) => ({ pid: metric.pid, type: metric.type, cpuPercent: metric.cpu.percentCPUUsage, workingSetSize: metric.memory.workingSetSize, })), windows: BrowserWindow.getAllWindows().length, webContents: webContents.getAllWebContents().length, background: { activity: lifecycle?.getActivity() ?? { visible: true, module: null }, leaseCount: lifecycle?.getLeaseCount() ?? 0, }, }; }