#!/usr/bin/env nu # Minimal Library - Fast path for interactive commands # NO config loading, NO platform bootstrap # Follows: @.claude/guidelines/nushell/NUSHELL_GUIDELINES.md # Error handling: Result pattern (hybrid, no try-catch) use lib_provisioning/result.nu * # Get user config path (centralized location) # Rule 2: Single purpose function # Cross-platform support (macOS, Linux, Windows) def get-user-config-path [] { let home = $env.HOME let os_name = (uname | get operating-system | str downcase) let config_path = match $os_name { "darwin" => $"($home)/Library/Application Support/provisioning/user_config.yaml", _ => $"($home)/.config/provisioning/user_config.yaml" } $config_path | path expand } # List all registered workspaces # Rule 1: Explicit types, Rule 4: Early returns # Rule 2: Single purpose - only list workspaces # Result: {ok: list, err: null} on success; {ok: null, err: message} on error export def workspace-list [] { let user_config = (get-user-config-path) # Guard: Early return if config doesn't exist if not ($user_config | path exists) { return (ok []) } # Guard: File is guaranteed to exist, open directly (no try-catch) let config = (open $user_config) let active = ($config | get --optional active_workspace | default "") let workspaces = ($config | get --optional workspaces | default []) # Guard: No workspaces registered if ($workspaces | length) == 0 { return (ok []) } # Pure transformation let result = ($workspaces | each {|ws| { name: $ws.name path: $ws.path active: ($ws.name == $active) last_used: ($ws | get --optional last_used | default "Never") } }) ok $result } # Get active workspace name # Rule 1: Explicit types, Rule 4: Early returns # Result: {ok: string, err: null} on success; {ok: null, err: message} on error export def workspace-active [] { let user_config = (get-user-config-path) # Guard: Config doesn't exist if not ($user_config | path exists) { return (ok "") } # Guard: File exists, read directly let active_name = (open $user_config | get --optional active_workspace | default "") ok $active_name } # Get workspace info by name # Rule 1: Explicit types, Rule 4: Early returns # Result: {ok: record, err: null} on success; {ok: null, err: message} on error export def workspace-info [name: string] { # Guard: Input validation if ($name | is-empty) { return (err "workspace name is required") } let user_config = (get-user-config-path) # Guard: Config doesn't exist if not ($user_config | path exists) { return (ok {name: $name, path: "", exists: false}) } # Guard: File exists, read directly let config = (open $user_config) let workspaces = ($config | get --optional workspaces | default []) let ws = ($workspaces | where { $in.name == $name } | first) # Guard: Workspace not found if ($ws | is-empty) { return (ok {name: $name, path: "", exists: false, default_infra: "", infrastructures: []}) } # Collect infra dirs with server counts let infra_root = ($ws.path | path join 'infra') let infrastructures = if ($infra_root | path exists) { ls $infra_root | where type == 'dir' | each {|inf| let inf_name = ($inf.name | path basename) let sf_direct = ($infra_root | path join $inf_name | path join 'servers.ncl') let sf_defs = ($infra_root | path join $inf_name | path join 'defs' | path join 'servers.ncl') let sf = if ($sf_direct | path exists) { $sf_direct } else { $sf_defs } let server_count = if ($sf | path exists) { open $sf --raw | split row "\n" | where {|l| $l =~ 'hostname\s*=\s*"' } | length } else { 0 } { name: $inf_name, servers: $server_count } } } else { [] } ok { name: $ws.name path: $ws.path exists: true last_used: ($ws | get --optional last_used | default "Never") default_infra: ($ws | get --optional default_infra | default "") infrastructures: $infrastructures } } # Quick status check (orchestrator health + active workspace) # Rule 1: Explicit types, Rule 4: Early returns # Result: {ok: record, err: null} on success; {ok: null, err: message} on error export def status-quick [] { # Guard: HTTP check with do/complete pattern (no try-catch) let health_result = (do { http get --max-time 2sec "http://localhost:9090/health" } | complete) let orch_health = if ($health_result.exit_code == 0) { $health_result.stdout } else { null } let orch_status = if ($orch_health != null) { "running" } else { "stopped" } # Guard: Get active workspace safely let ws_result = (workspace-active) let active_ws = (if (is-ok $ws_result) { $ws_result.ok } else { "" }) # Pure transformation ok { orchestrator: $orch_status workspace: $active_ws timestamp: (date now | format date "%Y-%m-%d %H:%M:%S") } } # Display essential environment variables # Rule 1: Explicit types, Rule 8: Pure function (read-only) # Result: {ok: record, err: null} on success; {ok: null, err: message} on error export def env-quick [] { # Pure transformation with optional operator let vars = { PROVISIONING_ROOT: ($env.PROVISIONING_ROOT? | default "not set") PROVISIONING_ENV: ($env.PROVISIONING_ENV? | default "not set") PROVISIONING_DEBUG: ($env.PROVISIONING_DEBUG? | default "false") HOME: $env.HOME PWD: $env.PWD } ok $vars } # Show quick help for fast-path commands # Rule 1: Explicit types, Rule 8: Pure function export def quick-help [] { "Provisioning CLI - Fast Path Commands Quick Commands (< 100ms): workspace list List all registered workspaces workspace active Show currently active workspace status Quick health check env Show essential environment variables help [command] Show help for a command For full help: provisioning help Show all available commands provisioning help Show help for specific command" }