Improve attachment memory safety, downloads, and high-memory alert UX.
All checks were successful
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 9m2s
Queue Release Build / build-windows (push) Successful in 28m8s
Queue Release Build / build-linux (push) Successful in 47m26s
Queue Release Build / build-android (push) Successful in 19m52s
Queue Release Build / finalize (push) Successful in 4m42s

Stream large receives to disk with chunk acks to cap renderer RAM, evict
off-screen display blobs, and route exports through a disk-aware download
service. Fix the high-memory dialog (backdrop dismiss, copy, log actions),
allow diagnostics paths in the path jail, and restore persisted image
hydration after reload.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-14 00:25:22 +02:00
parent f0d79aa627
commit bb0ac930ad
69 changed files with 2306 additions and 430 deletions

View File

@@ -0,0 +1,80 @@
import type { BrowserWindow } from 'electron';
import type { AppMetricsSnapshot } from '../app-metrics';
import { buildHighMemoryDiagnosticPayload } from './high-memory-snapshot.rules';
import { collectImmediateRendererSamples } from './immediate-renderer-samples.collector';
import { collectSessionContext } from './session-context.collector';
import type { HighMemoryAlertRecord } from './high-memory-alert.store';
import type { PerfDiagEntry } from './diagnostics.models';
import { PerfDiagWriter } from './diagnostics.writer';
export type HighMemoryCaptureReason = 'manual' | 'threshold';
export interface CaptureHighMemoryDiagnosticsInput {
userDataPath: string;
sessionStartedAt: number;
metrics: AppMetricsSnapshot;
totalWorkingSetKb: number;
writer: PerfDiagWriter | null;
mainWindow: BrowserWindow | null;
reason: HighMemoryCaptureReason;
}
export async function captureHighMemoryDiagnostics(
input: CaptureHighMemoryDiagnosticsInput
): Promise<HighMemoryAlertRecord> {
const detectedAt = Date.now();
const writer = input.writer ?? new PerfDiagWriter({
userDataPath: input.userDataPath,
sessionId: `${input.reason}-${detectedAt.toString(36)}-${process.pid}`
});
const immediateRendererEntries = await collectImmediateRendererSamples(input.mainWindow);
const environment = collectSessionContext({
sessionStartedAt: input.sessionStartedAt,
userDataPath: input.userDataPath
});
appendEntries(writer, immediateRendererEntries);
appendEntries(writer, [
{
collectedAt: detectedAt,
source: 'main',
type: 'environment',
payload: {
...environment
}
},
{
collectedAt: detectedAt,
source: 'main',
type: 'high-memory',
payload: buildHighMemoryDiagnosticPayload({
detectedAt,
totalWorkingSetKb: input.totalWorkingSetKb,
metrics: input.metrics,
environment,
mainProcessMemory: process.memoryUsage(),
ringEntries: writer.bufferedEntries,
immediateRendererEntries,
sessionId: writer.sessionId
})
}
]);
await writer.flushSnapshot(
input.reason === 'manual' ? 'manual-export' : 'high-memory-threshold'
);
return {
logFilePath: writer.snapshotFilePath,
detectedAt,
peakWorkingSetKb: input.totalWorkingSetKb,
sessionId: writer.sessionId,
reason: input.reason
};
}
function appendEntries(writer: PerfDiagWriter, entries: readonly PerfDiagEntry[]): void {
for (const entry of entries) {
writer.append(entry);
}
}