/** Format a duration in milliseconds to a human-readable string. */ export function formatDuration(ms: number): string { if (ms < 1000) return "<1s"; const seconds = Math.floor(ms / 1000); if (seconds < 60) return `${seconds}s`; const minutes = Math.floor(seconds / 60); const remaining = seconds % 60; return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`; } /** Truncate text to `max` characters, appending "..." if truncated. */ export function truncateText(text: string, max: number): string { const cleaned = text.replace(/\s+/g, " ").trim(); if (cleaned.length <= max) return cleaned; return cleaned.slice(0, max).trim() + "..."; } /** * Format an uptime duration in milliseconds with progressive * granularity, so short-lived sandboxes don't render as "0d 0h". * - < 60s → "Ns" * - < 60m → "Nm Ss" * - < 24h → "Nh Mm" * - otherwise → "Nd Hh" */ export function formatUptime(ms: number): string { if (!Number.isFinite(ms) || ms < 0) return "—"; const totalSeconds = Math.floor(ms / 1000); if (totalSeconds < 60) return `${totalSeconds}s`; const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; if (minutes < 60) return `${minutes}m ${seconds}s`; const hours = Math.floor(minutes / 60); const remMinutes = minutes % 60; if (hours < 24) return `${hours}h ${remMinutes}m`; const days = Math.floor(hours / 24); const remHours = hours % 24; return `${days}d ${remHours}h`; } /** * Format a byte count using binary units (KiB/MiB/GiB, surfaced as * "KB/MB/GB" for readability). KB and MB use one decimal below 10 and * round above; GB keeps two decimals below 10 so half-GB changes stay * visible on memory dashboards, and drops to one decimal above. */ export function formatBytes(bytes: number): string { if (!Number.isFinite(bytes) || bytes < 0) return "—"; if (bytes < 1024) return `${Math.round(bytes)} B`; const kb = bytes / 1024; if (kb < 1024) return `${kb < 10 ? kb.toFixed(1) : Math.round(kb)} KB`; const mb = kb / 1024; if (mb < 1024) return `${mb < 10 ? mb.toFixed(1) : Math.round(mb)} MB`; const gb = mb / 1024; return `${gb < 10 ? gb.toFixed(2) : gb.toFixed(1)} GB`; }