UNPKG

@vigilbase/cli

Version:

Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.

80 lines (79 loc) • 2.85 kB
import { sanitizeTerminal } from './format.js'; const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; const BAR_WIDTH = 24; function renderBar(ratio) { const clamped = Math.max(0, Math.min(1, ratio)); const filled = Math.round(clamped * BAR_WIDTH); const empty = BAR_WIDTH - filled; return `${'█'.repeat(filled)}${'░'.repeat(empty)}`; } /** * Live indeterminate progress on stderr while a scan/request is in flight. * Disabled for --json, non-TTY, CI, and NO_COLOR-style quiet environments. */ export function startProgress(label, options) { label = sanitizeTerminal(label).replace(/[\n\t]/g, ' '); const stream = options.stderr ?? process.stderr; if (!options.isEnabled) { return { stop: () => undefined }; } const expectedMs = options.expectedMs ?? 8_000; const started = Date.now(); let frame = 0; let closed = false; const draw = () => { if (closed) return; const elapsedMs = Date.now() - started; const elapsedSec = (elapsedMs / 1000).toFixed(1); // Ease toward ~90% at expectedMs, then creep slowly so we never hit 100% early. const ratio = 1 - Math.exp(-elapsedMs / expectedMs); const soft = Math.min(0.92, ratio); const spin = SPINNER[frame % SPINNER.length]; frame += 1; const line = `\r${spin} ${label} ${renderBar(soft)} ${elapsedSec}s`; stream.write(line); }; draw(); const timer = setInterval(draw, 80); timer.unref?.(); return { stop: (finalMessage) => { if (closed) return; closed = true; clearInterval(timer); const elapsedSec = ((Date.now() - started) / 1000).toFixed(1); const clear = `\r${' '.repeat(Math.max(60, label.length + BAR_WIDTH + 20))}\r`; stream.write(clear); if (finalMessage) { stream.write(`${sanitizeTerminal(finalMessage).replace(/[\n\t]/g, ' ')} (${elapsedSec}s)\n`); } }, }; } export function shouldShowProgress(mode, env = process.env, stderr = process.stderr) { if (mode === 'json') return false; if (env.CI === '1' || env.CI === 'true') return false; if (env.VIGILBASE_CLI_NO_PROGRESS === '1') return false; return Boolean(stderr.isTTY); } /** Tiny helper so call sites stay readable. */ export async function withProgress(label, mode, work, writer) { const progress = startProgress(label, { isEnabled: shouldShowProgress(mode), stderr: writer ? undefined : process.stderr, }); try { const result = await work(); progress.stop(`✓ ${label}`); return result; } catch (error) { progress.stop(`✗ ${label}`); throw error; } }