import { existsSync, readFileSync, statSync } from 'fs'; const MB = 1024 * 1024; /** At or above this the package is refused: GitHub warns at 50 MB and rejects at 100 MB. */ export const PATCH_MAX_BYTES = 49 * MB; export const PATCH_WARN_BYTES = 10 * MB; export const PATCH_BINARY_FILE_WARN_BYTES = 1 * MB; export interface PatchSizeReport { bytes: number; errors: string[]; warnings: string[]; } function fmt(bytes: number): string { return `${(bytes / MB).toFixed(1)} MB`; } /** Binary files in a `git diff --binary` patch whose size exceeds the threshold. */ export function largeBinaryFiles( patchText: string, thresholdBytes = PATCH_BINARY_FILE_WARN_BYTES ): { path: string; bytes: number }[] { const out: { path: string; bytes: number }[] = []; const lines = patchText.split('\n'); let current = ''; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const header = /^diff --git a\/.* b\/(.*)$/.exec(line); if (header) { current = header[1]; continue; } if (line === 'GIT binary patch') { const m = /^(?:literal|delta) (\d+)$/.exec(lines[i + 1] ?? ''); const bytes = m ? parseInt(m[1], 10) : 0; if (bytes > thresholdBytes) out.push({ path: current, bytes }); } } return out; } export function checkWorkspacePatchSize(patchPath: string): PatchSizeReport { const report: PatchSizeReport = { bytes: 0, errors: [], warnings: [] }; if (!existsSync(patchPath)) return report; report.bytes = statSync(patchPath).size; if (report.bytes >= PATCH_MAX_BYTES) { report.errors.push( `environment/workspace.patch is ${fmt(report.bytes)} — the limit is ${fmt(PATCH_MAX_BYTES)}. ` + 'Remove large files (model weights, datasets, archives, build output) and regenerate the patch; ' + 'use a tiny dummy fixture or a stub instead.' ); return report; } if (report.bytes >= PATCH_WARN_BYTES) { report.warnings.push( `environment/workspace.patch is ${fmt(report.bytes)} (limit ${fmt(PATCH_MAX_BYTES)}) — ` + 'check it contains only what the task needs' ); } for (const f of largeBinaryFiles(readFileSync(patchPath, 'latin1'))) { report.warnings.push( `workspace.patch adds a ${fmt(f.bytes)} binary file: ${f.path} — ` + 'prefer a tiny dummy fixture (e.g. a small random-init checkpoint) or a stub' ); } return report; }