# System Status Module # Provides comprehensive system status checks for provisioning platform use std log # Selective imports (ADR-025 Phase 3 Layer 2). # plugins/mod.nu star-import was dead — dropped. use platform/config/accessor/core.nu [config-get] use platform/user/config.nu [load-user-config] # Check Nushell version meets requirements def check-nushell-version [] { let current = (version).version let required = "0.107.1" let meets_requirement = (($current | str contains $required) or ($current >= $required)) { component: "Nushell" status: (if $meets_requirement { "✅" } else { "❌" }) version: $current required: $required message: (if $meets_requirement { "Version OK" } else { $"Update required: ($required)+" }) docs: "https://nushell.sh" } } # Check if Nickel is installed def check-nickel-installed [] { let nickel_bin = (which nickel | get path.0? | default "") let installed = ($nickel_bin | is-not-empty) let version_info = if $installed { let result = (do { ^nickel --version } | complete) if $result.exit_code == 0 { let version_full = ($result.stdout | str trim) # Extract version number and revision: "X.Y.Z (rev ...)" let version_short = ($version_full | str replace 'nickel-lang-cli nickel ' '') $version_short } else { "unknown" } } else { "not installed" } { component: "Nickel CLI" status: (if $installed { "✅" } else { "❌" }) version: $version_info required: "0.11.2+" message: (if $installed { "Installed and available" } else { "Not found in PATH" }) docs: "https://nickel-lang.io/docs/user_docs/getting-started/install" } } # Check required Nushell plugins def check-plugins [] { let required_plugins = [ { name: "nickel" description: "Nickel integration" optional: true docs: "docs/user/PLUGIN_INTEGRATION_GUIDE.md" } { name: "tera" description: "Template rendering" optional: false docs: "docs/user/PLUGIN_INTEGRATION_GUIDE.md" } { name: "auth" description: "Authentication" optional: true docs: "docs/user/AUTHENTICATION_LAYER_GUIDE.md" } { name: "kms" description: "Key management" optional: true docs: "docs/user/RUSTYVAULT_KMS_GUIDE.md" } { name: "orchestrator" description: "Orchestrator integration" optional: true docs: ".claude/features/orchestrator-architecture.md" } ] # Get list of registered plugins - use plugin list which returns structured data let installed = (plugin list) $required_plugins | each {|plugin| let is_installed = ($installed | any {|p| $p.name == $plugin.name}) { component: $plugin.name status: (if $is_installed { "✅" } else if $plugin.optional { "⚠️" } else { "❌" }) version: (if $is_installed { "registered" } else { "not registered" }) required: (if $plugin.optional { "optional" } else { "required" }) message: (if $is_installed { $plugin.description } else if $plugin.optional { $"($plugin.description) - optional, HTTP fallback available" } else { $"($plugin.description) - required for functionality" }) docs: $plugin.docs } } } # Check active workspace configuration def check-workspace [] { let user_config = (load-user-config) let active = ($user_config.active_workspace? | default null) if $active == null { return { component: "Active Workspace" status: "❌" version: "none" required: "configured" message: "No active workspace set" docs: "docs/user/WORKSPACE_SWITCHING_GUIDE.md" } } let workspace = ($user_config.workspaces | where name == $active | first) let ws_path = ($workspace.path? | default "") let ws_exists = ($ws_path | path exists) { component: "Active Workspace" status: (if $ws_exists { "✅" } else { "❌" }) version: $active required: "configured" message: (if $ws_exists { $"Using ($active) at ($ws_path)" } else { $"Workspace ($active) path not found" }) docs: "docs/user/WORKSPACE_SWITCHING_GUIDE.md" } } # Check available providers def check-providers [] { let providers_path = config-get "paths.providers" "provisioning/catalog/providers" let available_providers = if ($providers_path | path exists) { ls $providers_path | where type == dir | where { |item| let provider_name = ($item.name | path basename) let bin_install_sh = ($providers_path | path join $provider_name | path join "bin" | path join "install.sh" | path exists) let bin_install_nu = ($providers_path | path join $provider_name | path join "bin" | path join "install.nu" | path exists) $bin_install_sh or $bin_install_nu } | get name | path basename | str join ", " } else { "none" } let has_providers = ($available_providers != "none") { component: "Cloud Providers" status: (if $has_providers { "✅" } else { "⚠️" }) version: $available_providers required: "at least one" message: (if $has_providers { $"Available: ($available_providers)" } else { "No providers found" }) docs: "docs/architecture/multi-repo-strategy.md" } } # Check orchestrator service def check-orchestrator [] { let orchestrator_url = (config-get "platform.orchestrator.url" "http://localhost:9011") # Try to ping orchestrator health endpoint (handle connection errors gracefully) let result = (do { ^curl -s -f $"($orchestrator_url)/health" --max-time 2 } | complete) let is_running = ($result.exit_code == 0) { component: "Orchestrator Service" status: (if $is_running { "✅" } else { "⚠️" }) version: (if $is_running { $"running on ($orchestrator_url)" } else { "not running" }) required: "recommended" message: (if $is_running { "Service healthy and responding" } else { "Optional service not running. Review startup options" }) docs: ".claude/features/orchestrator-architecture.md" } } # Check platform services def check-platform-services [] { let services = [ { name: "Control Center" port: (config-get "control_center.port" 8080) optional: true docs: "provisioning/platform/control-center/README.md" } { name: "MCP Server" port: (config-get "mcp_server.port" 3000) optional: true docs: "provisioning/platform/mcp-server/README.md" } { name: "API Gateway" port: (config-get "api_gateway.port" 8090) optional: true docs: "provisioning/platform/api-gateway/README.md" } ] $services | each {|svc| let result = (do { ^curl -s -f $"http://localhost:($svc.port)/health" --max-time 1 } | complete) let is_running = ($result.exit_code == 0) { component: $svc.name status: (if $is_running { "✅" } else { "⚠️" }) version: (if $is_running { $"running on :($svc.port)" } else { "not running" }) required: "optional" message: (if $is_running { "Service available" } else { "Service not running - optional" }) docs: $svc.docs } } } # Collect all status checks # Refactored to use immutable pattern per Rule 3 (Nushell 0.110.0 compatibility) def get-all-checks [] { # Concatenate all check results immutably [ (check-nushell-version) (check-nickel-installed) (check-plugins) (check-workspace) (check-providers) (check-orchestrator) (check-platform-services) ] | flatten } # Main system status command # Comprehensive system status check showing all component states export def "provisioning status" [] { print $"(ansi cyan_bold)Provisioning Platform Status(ansi reset)\n" let all_checks = (get-all-checks) let results = ($all_checks | select component status version message) print ($results | table) } # Get status summary (machine-readable) export def "provisioning status-json" [] { let all_checks = (get-all-checks) let total = ($all_checks | length) let passing = ($all_checks | where status == "✅" | length) let warnings = ($all_checks | where status == "⚠️" | length) let failing = ($all_checks | where status == "❌" | length) { timestamp: (date now | format date "%Y-%m-%dT%H:%M:%SZ") summary: { total: $total passing: $passing warnings: $warnings failing: $failing health_percentage: (($passing / $total) * 100 | math round) } checks: $all_checks ready_for_deployment: ($failing == 0) } }