using System.Globalization; using System.Text.Json; using Microsoft.Extensions.DependencyInjection; using Spectre.Console; using StellaOps.ExportCenter.Core.EvidenceCache; namespace StellaOps.Cli.Commands; internal static partial class CommandHandlers { internal static async Task HandleExportCacheStatsAsync( IServiceProvider services, string scanOutputPath, bool json, bool verbose, CancellationToken cancellationToken) { SetVerbosity(services, verbose); if (string.IsNullOrWhiteSpace(scanOutputPath)) { AnsiConsole.MarkupLine("[red]Scan output path is required.[/]"); return 1; } scanOutputPath = Path.GetFullPath(scanOutputPath); if (!Directory.Exists(scanOutputPath)) { AnsiConsole.MarkupLine($"[red]Scan output directory not found:[/] {Markup.Escape(scanOutputPath)}"); return 1; } var cache = services.GetRequiredService(); var statistics = await cache.GetStatisticsAsync(scanOutputPath, cancellationToken).ConfigureAwait(false); if (json) { var payload = new { scanOutput = scanOutputPath, statistics }; AnsiConsole.WriteLine(JsonSerializer.Serialize(payload, JsonOptions)); return 0; } if (statistics.TotalBundles == 0) { AnsiConsole.MarkupLine("[yellow]No evidence cache entries found.[/]"); } var table = new Table().AddColumns("Field", "Value"); table.AddRow("Scan output", Markup.Escape(scanOutputPath)); table.AddRow("Total bundles", statistics.TotalBundles.ToString(CultureInfo.InvariantCulture)); table.AddRow("Fully available", statistics.FullyAvailable.ToString(CultureInfo.InvariantCulture)); table.AddRow("Partially available", statistics.PartiallyAvailable.ToString(CultureInfo.InvariantCulture)); table.AddRow("Pending enrichment", statistics.PendingEnrichment.ToString(CultureInfo.InvariantCulture)); table.AddRow("Offline resolvable", FormattableString.Invariant($"{statistics.OfflineResolvablePercentage:0.##}%")); table.AddRow("Total size", FormatBytes(statistics.TotalSizeBytes)); AnsiConsole.Write(table); return 0; } internal static async Task HandleExportCacheProcessQueueAsync( IServiceProvider services, string scanOutputPath, bool json, bool verbose, CancellationToken cancellationToken) { SetVerbosity(services, verbose); if (string.IsNullOrWhiteSpace(scanOutputPath)) { AnsiConsole.MarkupLine("[red]Scan output path is required.[/]"); return 1; } scanOutputPath = Path.GetFullPath(scanOutputPath); if (!Directory.Exists(scanOutputPath)) { AnsiConsole.MarkupLine($"[red]Scan output directory not found:[/] {Markup.Escape(scanOutputPath)}"); return 1; } var cache = services.GetRequiredService(); var result = await cache.ProcessEnrichmentQueueAsync(scanOutputPath, cancellationToken).ConfigureAwait(false); if (json) { var payload = new { scanOutput = scanOutputPath, result }; AnsiConsole.WriteLine(JsonSerializer.Serialize(payload, JsonOptions)); return 0; } var table = new Table().AddColumns("Field", "Value"); table.AddRow("Scan output", Markup.Escape(scanOutputPath)); table.AddRow("Processed", result.ProcessedCount.ToString(CultureInfo.InvariantCulture)); table.AddRow("Failed", result.FailedCount.ToString(CultureInfo.InvariantCulture)); table.AddRow("Remaining", result.RemainingCount.ToString(CultureInfo.InvariantCulture)); AnsiConsole.Write(table); return 0; } }