# Provider Registry System # Dynamic provider discovery, registration, and management use ../config/accessor.nu * use interface.nu * # Provider registry cache file path def get-provider-cache-file []: nothing -> string { let cache_dir = ($env.HOME | path join ".cache" "provisioning") if not ($cache_dir | path exists) { mkdir $cache_dir } $cache_dir | path join "provider-registry.json" } # Check if registry is initialized def is-registry-initialized []: nothing -> bool { ($env.PROVIDER_REGISTRY_INITIALIZED? | default false) } # Mark registry as initialized def mark-registry-initialized []: nothing -> nothing { $env.PROVIDER_REGISTRY_INITIALIZED = true } # Initialize the provider registry export def init-provider-registry []: nothing -> nothing { if (is-registry-initialized) { return } # Check if cache exists and is recent (less than 1 hour old) let cache_file = (get-provider-cache-file) if ($cache_file | path exists) { let cache_age = ((date now) - (ls $cache_file | get 0.modified)) if ($cache_age | into int) < 3600_000_000_000 { # 1 hour in nanoseconds # Use cached registry mark-registry-initialized return } } print "🔄 Initializing provider registry..." # Discover and cache providers discover-and-register-providers mark-registry-initialized } # Get provider registry from cache or discover def get-provider-registry []: nothing -> record { let cache_file = (get-provider-cache-file) if ($cache_file | path exists) { open $cache_file } else { discover-providers-only } } # Discover providers without full registration def discover-providers-only []: nothing -> record { mut registry = {} # Get provisioning system path from config or environment let base_path = (config-get "provisioning.path" ($env.PROVISIONING? | default "/Users/Akasha/project-provisioning/provisioning")) # Core providers let core_providers_path = ($base_path | path join "core" "nulib" "providers") if ($core_providers_path | path exists) { let core_providers = (discover-providers-in-directory $core_providers_path "core") $registry = ($registry | merge $core_providers) } # Extension providers let extension_providers_path = ($base_path | path join "extensions" "providers") if ($extension_providers_path | path exists) { let extension_providers = (discover-providers-in-directory $extension_providers_path "extension") $registry = ($registry | merge $extension_providers) } $registry } # Discover and register all providers def discover-and-register-providers []: nothing -> nothing { let registry = (discover-providers-only) # Save to cache let cache_file = (get-provider-cache-file) $registry | to json | save --force $cache_file print $"✅ Discovered ($registry | columns | length) providers" } # Discover providers in a specific directory def discover-providers-in-directory [base_path: string, provider_type: string]: nothing -> record { mut providers = {} if not ($base_path | path exists) { return $providers } # Look for provider.nu files in subdirectories let provider_dirs = (ls $base_path | where type == dir | get name) for dir in $provider_dirs { let provider_file = ($dir | path join "provider.nu") if ($provider_file | path exists) { let provider_name = ($dir | path basename) # Check if provider has metadata function (just test it's valid) # We don't parse the metadata here, just verify the provider loads let has_metadata = (do { nu -c $"use ($provider_file) *; get-provider-metadata | ignore" } | complete | get exit_code) == 0 if $has_metadata { let provider_info = { name: $provider_name type: $provider_type path: $dir entry_point: $provider_file available: true loaded: false last_discovered: (date now) } $providers = ($providers | insert $provider_name $provider_info) print $" 📦 Found ($provider_type) provider: ($provider_name)" } else { print $" ⚠️ Invalid provider: ($provider_name)" } } } $providers } # List all available providers export def list-providers [ --available-only # Only show available providers --verbose # Show detailed information ]: nothing -> table { if not (is-registry-initialized) { init-provider-registry | ignore } let registry = (get-provider-registry) let providers = ($registry | transpose name details) let filtered = if $available_only { $providers | where {|p| $p.details.available == true} } else { $providers } if $verbose { $filtered | select name details.type details.available details.loaded details.path details.last_discovered } else { $filtered | select name details.type details.available details.loaded } } # Check if a provider is available export def is-provider-available [provider_name: string]: nothing -> bool { if not (is-registry-initialized) { init-provider-registry | ignore } let registry = (get-provider-registry) if ($provider_name in ($registry | columns)) { let provider = ($registry | get $provider_name) $provider.available } else { false } } # Get provider entry information export def get-provider-entry [provider_name: string]: nothing -> record { if not (is-registry-initialized) { init-provider-registry | ignore } let registry = (get-provider-registry) if ($provider_name in ($registry | columns)) { $registry | get $provider_name } else { error make { msg: $"Provider ($provider_name) not found in registry" } } } # Get provider registry statistics export def get-provider-stats []: nothing -> record { if not (is-registry-initialized) { init-provider-registry | ignore } let registry = (get-provider-registry) let providers = ($registry | transpose name details) { total_providers: ($providers | length) available_providers: ($providers | where {|p| $p.details.available == true} | length) core_providers: ($providers | where {|p| $p.details.type == "core"} | length) extension_providers: ($providers | where {|p| $p.details.type == "extension"} | length) loaded_providers: ($providers | where {|p| $p.details.loaded == true} | length) } } # Get capabilities for a specific provider export def get-provider-capabilities-for [provider_name: string]: nothing -> record { if not (is-provider-available $provider_name) { return {} } let provider_entry = (get-provider-entry $provider_name) let metadata_cmd = $"nu -c \"use ($provider_entry.entry_point) *; get-provider-metadata\"" let result = (nu -c $metadata_cmd | complete) if $result.exit_code == 0 { let metadata = ($result.stdout | from json) $metadata.capabilities? | default {} } else { {} } } # Refresh the provider registry export def refresh-provider-registry []: nothing -> nothing { # Clear cache let cache_file = (get-provider-cache-file) if ($cache_file | path exists) { rm $cache_file } # Reset initialization flag $env.PROVIDER_REGISTRY_INITIALIZED = false # Reinitialize init-provider-registry | ignore } # Export environment setup export-env { $env.PROVIDER_REGISTRY_INITIALIZED = false }