| |
| |
| |
| |
| |
|
|
| import { |
| REFERENCE_CONTENT_START, |
| REFERENCE_CONTENT_END, |
| } from '@google/gemini-cli-core'; |
|
|
| export const formatBytes = (bytes: number): string => { |
| const gb = bytes / (1024 * 1024 * 1024); |
| if (bytes < 1024 * 1024) { |
| return `${(bytes / 1024).toFixed(1)} KB`; |
| } |
| if (bytes < 1024 * 1024 * 1024) { |
| return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; |
| } |
| return `${gb.toFixed(2)} GB`; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| export const formatDuration = (milliseconds: number): string => { |
| if (milliseconds <= 0) { |
| return '0s'; |
| } |
|
|
| if (milliseconds < 1000) { |
| return `${Math.round(milliseconds)}ms`; |
| } |
|
|
| const totalSeconds = milliseconds / 1000; |
|
|
| if (totalSeconds < 60) { |
| return `${totalSeconds.toFixed(1)}s`; |
| } |
|
|
| const hours = Math.floor(totalSeconds / 3600); |
| const minutes = Math.floor((totalSeconds % 3600) / 60); |
| const seconds = Math.floor(totalSeconds % 60); |
|
|
| const parts: string[] = []; |
|
|
| if (hours > 0) { |
| parts.push(`${hours}h`); |
| } |
| if (minutes > 0) { |
| parts.push(`${minutes}m`); |
| } |
| if (seconds > 0) { |
| parts.push(`${seconds}s`); |
| } |
|
|
| |
| if (parts.length === 0) { |
| if (hours > 0) return `${hours}h`; |
| if (minutes > 0) return `${minutes}m`; |
| return `${seconds}s`; |
| } |
|
|
| return parts.join(' '); |
| }; |
|
|
| export const formatTimeAgo = (date: string | number | Date): string => { |
| const past = new Date(date); |
| if (isNaN(past.getTime())) { |
| return 'invalid date'; |
| } |
|
|
| const now = new Date(); |
| const diffMs = now.getTime() - past.getTime(); |
| if (diffMs < 60000) { |
| return 'just now'; |
| } |
| return `${formatDuration(diffMs)} ago`; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function stripReferenceContent(text: string): string { |
| |
| const pattern = new RegExp( |
| `\\n?${REFERENCE_CONTENT_START}[\\s\\S]*?${REFERENCE_CONTENT_END}`, |
| 'g', |
| ); |
|
|
| return text.replace(pattern, '').trim(); |
| } |
|
|
| export const formatResetTime = ( |
| resetTime: string | undefined, |
| format: 'terse' | 'column' | 'full' = 'full', |
| ): string => { |
| if (!resetTime) return ''; |
| const resetDate = new Date(resetTime); |
| if (isNaN(resetDate.getTime())) return ''; |
|
|
| const diff = resetDate.getTime() - Date.now(); |
| if (diff <= 0) return ''; |
|
|
| const totalMinutes = Math.ceil(diff / (1000 * 60)); |
| const hours = Math.floor(totalMinutes / 60); |
| const minutes = totalMinutes % 60; |
|
|
| const isTerse = format === 'terse'; |
| const isColumn = format === 'column'; |
|
|
| if (isTerse || isColumn) { |
| const hoursStr = hours > 0 ? `${hours}h` : ''; |
| const minutesStr = minutes > 0 ? `${minutes}m` : ''; |
| const duration = |
| hoursStr && minutesStr |
| ? `${hoursStr} ${minutesStr}` |
| : hoursStr || minutesStr; |
|
|
| if (isColumn) { |
| const timeStr = new Intl.DateTimeFormat('en-US', { |
| hour: 'numeric', |
| minute: 'numeric', |
| }).format(resetDate); |
| return duration ? `${timeStr} (${duration})` : timeStr; |
| } |
|
|
| return duration; |
| } |
|
|
| let duration = ''; |
| if (hours > 0) { |
| duration = `${hours} hour${hours > 1 ? 's' : ''}`; |
| if (minutes > 0) { |
| duration += ` ${minutes} minute${minutes > 1 ? 's' : ''}`; |
| } |
| } else { |
| duration = `${minutes} minute${minutes > 1 ? 's' : ''}`; |
| } |
|
|
| const timeStr = new Intl.DateTimeFormat('en-US', { |
| hour: 'numeric', |
| minute: 'numeric', |
| timeZoneName: 'short', |
| }).format(resetDate); |
|
|
| return `${duration} at ${timeStr}`; |
| }; |
|
|