# Cache Management CLI Commands # Provides user-facing commands for cache operations and configuration # Follows Nushell 0.109.0+ guidelines # Selective imports (ADR-025 Phase 3 Layer 2). # cache/metadata star-import was dead — dropped. use domain/cache/core.nu [cache-clear-type get-cache-stats] # Avoid importing all modules - use only what's needed # use ./config_manager.nu * # use ./nickel.nu * # use ./sops.nu * # use ./final.nu * # ============================================================================ # Data Operations: Clear, List, Warm, Validate # ============================================================================ # Clear all or specific type of cache export def cache-clear [ --type: string = "all" # "all", "nickel", "sops", "final", "provider", "platform" --force = false # Skip confirmation ] { if (not $force) and ($type == "all") { let response = (input "Clear ALL cache? This cannot be undone. (yes/no): ") if $response != "yes" { print "Cancelled." return } } match $type { "all" => { print "Clearing all caches..." do { cache-clear-type "nickel" cache-clear-type "sops" cache-clear-type "final" cache-clear-type "provider" cache-clear-type "platform" } | complete | ignore print "✅ All caches cleared" }, "nickel" => { print "Clearing Nickel compilation cache..." clear-nickel-cache print "✅ Nickel cache cleared" }, "sops" => { print "Clearing SOPS decryption cache..." clear-sops-cache print "✅ SOPS cache cleared" }, "final" => { print "Clearing final configuration cache..." clear-final-cache print "✅ Final config cache cleared" }, _ => { print $"❌ Unknown cache type: ($type)" } } } # List cache entries export def cache-list [ --type: string = "*" # "nickel", "sops", "final", etc or "*" for all --format: string = "table" # "table", "json", "yaml" ] { let stats = (get-cache-stats) if ($stats.total_entries | is-empty) or ($stats.total_entries == 0) { print "📭 Cache is empty" return } let home = ($env.HOME? | default "~" | path expand) let base = ($home | path join ".provisioning" "cache" "config") mut entries = [] let type_dir = match $type { "all" => $base, "nickel" => ($base | path join "nickel"), "sops" => ($base | path join "sops"), "final" => ($base | path join "workspaces"), _ => ($base | path join $type) } if not ($type_dir | path exists) { print $"No cache directory for type: ($type)" return } for meta_file in (glob $"($type_dir)/**/*.meta") { let cache_file = ($meta_file | str substring 0..-6) let meta = (do { open $meta_file } | complete | get stdout) if $meta.exit_code == 0 { let size_result = (do { if ($cache_file | path exists) { $cache_file | stat | get size } else { 0 } } | complete) if $size_result.exit_code == 0 { let size_kb = ($size_result.stdout / 1024) let cache_type = ($meta_file | path dirname | path basename) $entries = ($entries | append { type: $cache_type, key: ($cache_file | path basename), size_kb: ($size_kb | math round -p 2), created: ($meta.stdout.created_at? | default "unknown"), expires: ($meta.stdout.expires_at? | default "unknown") }) } } } if ($entries | length) == 0 { print "📭 No cache entries found" return } match $format { "json" => { $entries | to json --indent 2 | print }, "yaml" => { $entries | to yaml | print }, _ => { print $"📦 Cache Entries (($entries | length)) total):\n" $entries | table } } } # Warm cache (pre-populate) export def cache-warm [ --workspace: string = "" --environment: string = "*" ] { print "🔥 Warming cache..." if ($workspace | is-empty) { # Try to get active workspace use ../../user/config.nu get-active-workspace let active = (get-active-workspace) if ($active | is-empty) { print "❌ No active workspace. Use: provisioning workspace activate " return } print $"Warming cache for workspace: ($active.name)" do { warm-nickel-cache $active.path } | complete | ignore } else { print $"Warming cache for workspace: ($workspace)" } print "✅ Cache warming complete" } # Validate cache integrity export def cache-validate [] { print "🔍 Validating cache integrity..." let home = ($env.HOME? | default "~" | path expand) let base = ($home | path join ".provisioning" "cache" "config") if not ($base | path exists) { return { valid: true, total_files: 0, errors: [], warnings: [] } } mut errors = [] mut warnings = [] mut total_files = 0 # Check SOPS permissions let sops_stats = (get-sops-cache-stats) if ($sops_stats.permission_errors | default 0) > 0 { $errors = ($errors | append $"SOPS cache: ($sops_stats.permission_errors) files with invalid permissions") } # Check all metadata files for meta_file in (glob $"($base)/**/*.meta") { $total_files += 1 let cache_file = ($meta_file | str substring 0..-6) let meta_result = (do { open $meta_file } | complete) if $meta_result.exit_code != 0 { $errors = ($errors | append $"Cannot read metadata: ($meta_file)") continue } let meta = $meta_result.stdout # Check expiration let now = (date now | format date "%Y-%m-%dT%H:%M:%SZ") if $now > $meta.expires_at { $warnings = ($warnings | append $"Expired cache: ($cache_file)") } } let result = { valid: ($errors | length) == 0, total_files: $total_files, errors: $errors, warnings: $warnings } if $result.valid { print "✅ Cache validation passed" } else { print "❌ Cache validation failed" for error in $errors { print $" ❌ ($error)" } } if ($warnings | length) > 0 { for warning in $warnings { print $" ⚠️ ($warning)" } } $result } # ============================================================================ # Configuration Commands: Show, Get, Set, Reset # ============================================================================ # Show cache configuration (enhanced with paths and all settings) export def cache-config-show [ --format: string = "table" ] { let config = (get-cache-config) print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" print "📋 Cache Configuration" print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" print "" print "▸ Core Settings:" print $" Enabled: ($config.enabled)" print $" Max Size: ($config.max_cache_size / 1048576 | math round -p 0) MB" print "" print "▸ Cache Location:" print $" Base Path: ($config.paths.base)" print "" print "▸ Time-To-Live (TTL) Settings:" print $" Final Config: ($config.ttl.final_config)s (5 minutes)" print $" Nickel Compilation: ($config.ttl.nickel_compilation)s (30 minutes)" print $" SOPS Decryption: ($config.ttl.sops_decryption)s (15 minutes)" print $" Provider Config: ($config.ttl.provider_config)s (10 minutes)" print $" Platform Config: ($config.ttl.platform_config)s (10 minutes)" print "" print "▸ Security Settings:" print $" SOPS File Permissions: ($config.security.sops_file_permissions)" print $" SOPS Dir Permissions: ($config.security.sops_dir_permissions)" print "" print "▸ Validation Settings:" print $" Strict mtime Checking: ($config.validation.strict_mtime)" print "" print "▸ Metadata:" print $" Last Modified: ($config.metadata.last_modified)" print $" Modified By: ($config.metadata.modified_by)" print $" Config Version: ($config.metadata.version)" print "" print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" } # Get specific cache configuration setting export def cache-config-get [ setting_path: string # "enabled", "ttl.final_config", etc. ] { let value = (cache-config-get $setting_path) if ($value | is-empty) { print $"Setting not found: ($setting_path)" return } print $"($setting_path): ($value)" $value } # Set cache configuration export def cache-config-set [ setting_path: string value: any ] { print $"Setting ($setting_path) = ($value)" cache-config-set $setting_path $value print "✅ Configuration updated" } # Reset cache configuration export def cache-config-reset [ setting_path?: string = "" ] { if ($setting_path | is-empty) { let confirm = (input "Reset ALL cache configuration to defaults? (yes/no): ") if $confirm != "yes" { print "Cancelled." return } cache-config-reset print "✅ All configuration reset to defaults" } else { print $"Resetting ($setting_path) to default..." cache-config-reset $setting_path print "✅ Setting reset to default" } } # Validate cache configuration export def cache-config-validate [] { print "Validating cache configuration..." let result = (cache-config-validate) if $result.valid { print "✅ Configuration is valid" } else { print "❌ Configuration has errors:" for error in $result.errors { print $" ❌ ($error)" } } if ($result.warnings | length) > 0 { print "⚠️ Warnings:" for warning in $result.warnings { print $" ⚠️ ($warning)" } } $result } # ============================================================================ # Monitoring: Status, Stats # ============================================================================ # Show comprehensive cache status (configuration + statistics) export def cache-status [] { let status = (get-cache-status) print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" print "📊 Cache Configuration" print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" let config = $status.configuration print $" Enabled: ($config.enabled)" print $" Max Size: ($status.max_size_mb) MB" print $" Current Usage: ($status.current_usage_percent)%" print "" print " TTL Settings:" print $" Final Config: ($config.ttl.final_config)s (5 min)" print $" Nickel Compilation: ($config.ttl.nickel_compilation)s (30 min)" print $" SOPS Decryption: ($config.ttl.sops_decryption)s (15 min)" print $" Provider Config: ($config.ttl.provider_config)s (10 min)" print $" Platform Config: ($config.ttl.platform_config)s (10 min)" print "" print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" print "📈 Cache Statistics" print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" let stats = $status.statistics print $" Total Entries: ($stats.total_entries)" print $" Total Size: ($stats.total_size_mb | math round -p 2) MB" print "" print " By Type:" let nickel_stats = (get-nickel-cache-stats) print $" Nickel: ($nickel_stats.total_entries) entries, ($nickel_stats.total_size_mb | math round -p 2) MB" let sops_stats = (get-sops-cache-stats) print $" SOPS: ($sops_stats.total_entries) entries, ($sops_stats.total_size_mb | math round -p 2) MB" let final_stats = (get-final-cache-stats) print $" Final Config: ($final_stats.total_entries) entries, ($final_stats.total_size_mb | math round -p 2) MB" print "" print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" } # Show cache statistics only export def cache-stats [ --format: string = "table" ] { let stats = (get-cache-stats) print $"📊 Cache Statistics\n" print $" Total Entries: ($stats.total_entries)" print $" Total Size: ($stats.total_size_mb | math round -p 2) MB" print "" let nickel_stats = (get-nickel-cache-stats) let sops_stats = (get-sops-cache-stats) let final_stats = (get-final-cache-stats) let summary = [ { type: "Nickel Compilation", entries: $nickel_stats.total_entries, size_mb: ($nickel_stats.total_size_mb | math round -p 2) }, { type: "SOPS Decryption", entries: $sops_stats.total_entries, size_mb: ($sops_stats.total_size_mb | math round -p 2) }, { type: "Final Config", entries: $final_stats.total_entries, size_mb: ($final_stats.total_size_mb | math round -p 2) } ] match $format { "json" => { $summary | to json --indent 2 | print }, "yaml" => { $summary | to yaml | print }, _ => { print "By Type:" $summary | table } } } # ============================================================================ # Helper: Dispatch cache commands # ============================================================================ # Main cache command dispatcher export def main [ ...args: string ] { if ($args | is-empty) { cache-status return } let command = ($args | get 0) let rest = (if ($args | length) > 1 { $args | skip 1 } else { [] }) match $command { "clear" => { let cache_type = ($rest | get 0 | default "all") cache-clear --type $cache_type }, "list" => { cache-list }, "warm" => { cache-warm }, "validate" => { cache-validate | ignore }, "config" => { let subcommand = ($rest | get 0 | default "show") match $subcommand { "show" => { cache-config-show }, "get" => { let path = ($rest | get 1 | default "") if ($path | is-empty) { print "Usage: cache config get " } else { cache-config-get $path | ignore } }, "set" => { let path = ($rest | get 1 | default "") let value = ($rest | get 2 | default "") if ($path | is-empty) or ($value | is-empty) { print "Usage: cache config set " } else { cache-config-set $path $value } }, "reset" => { let path = ($rest | get 1 | default "") cache-config-reset $path }, "validate" => { cache-config-validate | ignore }, _ => { print $"Unknown config subcommand: ($subcommand)" } } }, "status" => { cache-status }, "stats" => { cache-stats }, "help" => { print "Cache Management Commands: cache clear [--type ] Clear cache (all, nickel, sops, final) cache list List cache entries cache warm Pre-populate cache cache validate Validate cache integrity cache config show Show configuration cache config get Get specific setting cache config set Set configuration cache config reset [path] Reset to defaults cache config validate Validate configuration cache status Show full status (config + stats) cache stats Show statistics only cache help Show this help" }, _ => { print $"Unknown cache command: ($command)" print "Use 'cache help' for available commands" } } }