/** * Repository Size Checker * Handles checking repository sizes and enforcing limits */ import { existsSync, statSync } from 'fs'; import { readdir } from 'fs/promises'; import { join } from 'path'; import logger from '../logger.js'; /** * Repository Size Checker * Handles checking repository sizes and enforcing limits */ export class RepoSizeChecker { /** * Get repository size in bytes * Returns the total size of the repository directory */ async getRepoSize(repoPath: string): Promise { if (!existsSync(repoPath)) { return 0; } let totalSize = 0; async function calculateSize(dirPath: string): Promise { let size = 0; try { const entries = await readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = join(dirPath, entry.name); if (entry.isDirectory()) { size += await calculateSize(fullPath); } else if (entry.isFile()) { try { const stats = statSync(fullPath); size += stats.size; } catch { // Ignore errors accessing files } } } } catch { // Ignore errors accessing directories } return size; } totalSize = await calculateSize(repoPath); return totalSize; } /** * Check if repository size exceeds the maximum (2 GB) */ async checkRepoSizeLimit(repoPath: string, maxSizeBytes: number = 2 * 1024 * 1024 * 1024): Promise<{ withinLimit: boolean; currentSize: number; maxSize: number; error?: string }> { try { const currentSize = await this.getRepoSize(repoPath); const withinLimit = currentSize <= maxSizeBytes; return { withinLimit, currentSize, maxSize: maxSizeBytes, ...(withinLimit ? {} : { error: `Repository size (${(currentSize / 1024 / 1024 / 1024).toFixed(2)} GB) exceeds maximum (${(maxSizeBytes / 1024 / 1024 / 1024).toFixed(2)} GB)` }) }; } catch (error) { return { withinLimit: false, currentSize: 0, maxSize: maxSizeBytes, error: `Failed to check repository size: ${error instanceof Error ? error.message : String(error)}` }; } } }