/** Shared formatting helpers for the Project Home views. */ export function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`; } /** "2h ago" / "3d ago". Returns null for unparseable timestamps. */ export function formatAge(iso: string | null | undefined): string | null { if (!iso) return null; const then = Date.parse(iso); if (Number.isNaN(then)) return null; return formatElapsed(Date.now() - then); } export function formatElapsed(ms: number): string { const seconds = Math.max(0, Math.floor(ms / 1000)); if (seconds < 60) return "just now"; const minutes = Math.floor(seconds / 60); if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); if (hours < 24) return `${hours}h ${minutes % 60}m ago`; const days = Math.floor(hours / 24); return `${days}d ago`; } /** Uptime phrasing for a known start timestamp. */ export function formatUptime(startedAtMs: number | undefined): string | null { if (startedAtMs === undefined) return null; const seconds = Math.floor((Date.now() - startedAtMs) / 1000); if (seconds < 60) return "just started"; const minutes = Math.floor(seconds / 60); if (minutes < 60) return `up ${minutes}m`; const hours = Math.floor(minutes / 60); if (hours < 24) return `up ${hours}h ${minutes % 60}m`; return `up ${Math.floor(hours / 24)}d`; }