UNPKG

filecoin-pin

Version:

Bridge IPFS content to Filecoin Onchain Cloud using familiar tools

136 lines (121 loc) 3.22 kB
/** * Shared CLI helper utilities for consistent command-line experience */ import { cancel as clackCancel, intro as clackIntro, outro as clackOutro, spinner as clackSpinner, } from '@clack/prompts' import { isTTY, log } from './cli-logger.js' /** * Spinner interface for progress indication * Works in both TTY and non-TTY environments */ export type Spinner = { start: (msg: string) => void message: (msg: string) => void stop: (msg?: string) => void } /** * Creates a spinner that works in both TTY and non-TTY environments * * In TTY mode: Uses @clack/prompts spinner for nice visual feedback * In non-TTY mode: Prints simple status messages without ANSI codes */ export function createSpinner(): Spinner { if (isTTY()) { // Use the real spinner for TTY return clackSpinner() } else { // Non-TTY fallback - only print completion messages return { start(_msg: string) { // Don't print start messages in non-TTY }, message(_msg: string) { // Don't print progress messages in non-TTY }, stop(msg?: string) { if (msg) { // Only print the final completion message log.message(msg) } }, } } } /** * Show intro message with proper TTY handling */ export function intro(message: string): void { if (isTTY()) { clackIntro(message) } else { log.message(message) } } /** * Display a cancellation/error message * In TTY mode, uses clack's cancel for nice formatting * In non-TTY mode, prints to stderr */ export function cancel(message: string): void { if (isTTY()) { clackCancel(message) } else { console.error(message) } } /** * Display a success/completion message * In TTY mode, uses clack's outro for nice formatting * In non-TTY mode, prints to stdout */ export function outro(message: string): void { if (isTTY()) { clackOutro(message) } else { console.log(message) } } const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'] /** * Format file size for human-readable display */ export function formatFileSize(bytes: number | bigint): string { if (typeof bytes === 'bigint') { return formatFileSizeBigInt(bytes) } let size = bytes let unitIndex = 0 while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024 unitIndex++ } return `${size.toFixed(1)} ${units[unitIndex]}` } function formatFileSizeBigInt(bytes: bigint): string { let unitIndex = 0 let divisor = 1n while (bytes >= divisor * 1024n && unitIndex < units.length - 1) { divisor *= 1024n unitIndex++ } const divisorNumber = Number(divisor) const asNumber = Number(bytes) / divisorNumber const sizeFloat = Number.isFinite(asNumber) && asNumber > 0 ? asNumber : Number(bytes / divisor) + Number(bytes % divisor) / divisorNumber return `${sizeFloat.toFixed(1)} ${units[unitIndex]}` } /** * Check if we can perform interactive prompts. * * TTY is not enough, we also need to be in an interactive environment. * CI/CD environments are not interactive. */ export function isInteractive(): boolean { return isTTY() && process.env.CI !== 'true' && process.env.GITHUB_ACTIONS !== 'true' }