# Shell Command Handlers # Domain: Nushell environment, shell info, and resource listing # REMOVED: use ../../../lib_provisioning * - causes circular import use cli/flags.nu * # Validate infrastructure name is safe from path injection def validate_infra_name [infra: string] { # Returns true if INVALID (contains dangerous patterns) if ($infra | str contains "/") or ($infra | str contains "..") or ($infra | str starts-with "/") or ($infra | str contains " ") { return true } false } # Nu shell command handler - Start Nushell with provisioning library loaded export def handle_nu [ops: string, flags: record] { let run_ops = if ($ops | str trim | str starts-with "-") { "" } else { let parts = ($ops | split row " ") if ($parts | is-empty) { "" } else { $parts | first } } if ($flags.infra | is-not-empty) { # Validate infra name to prevent path injection if (validate_infra_name $flags.infra) { error make { msg: "Invalid infrastructure name - contains path traversal characters" } } if ($env.PROVISIONING_INFRA_PATH | path join $flags.infra | path exists) { cd ($env.PROVISIONING_INFRA_PATH | path join $flags.infra) } } if ($flags.output_format | is-empty) { if ($run_ops | is-empty) { print ( $"\nTo exit (_ansi purple_bold)NuShell(_ansi reset) session, with (_ansi default_dimmed)lib_provisioning(_ansi reset) loaded, " + $"use (_ansi green_bold)exit(_ansi reset) or (_ansi green_bold)[CTRL-D](_ansi reset)" ) # Pass the provisioning configuration files to the Nu subprocess # This ensures the interactive session has the same config loaded as the calling environment let config_path = ($env.PROVISIONING_CONFIG? | default "") # Build library paths argument - needed for module resolution during parsing # Convert colon-separated string to -I flag arguments let lib_dirs = ($env.NU_LIB_DIRS? | default "") let lib_paths = if ($lib_dirs | is-not-empty) { ($lib_dirs | split row ":" | where { |x| ($x | is-not-empty) }) } else { [] } if ($config_path | is-not-empty) { # Pass config files AND library paths via -I flags for module resolution # Library paths are set via -I flags which enables module resolution during parsing phase if ($lib_paths | length) > 0 { # Construct command with -I flags for each library path let cmd = (mut cmd_parts = []; for path in $lib_paths { $cmd_parts = ($cmd_parts | append "-I" | append $path) }; $cmd_parts) # Start interactive Nushell with provisioning configuration loaded # The -i flag enables interactive mode (REPL) with full terminal features ^nu --config $"($config_path)/config.nu" --env-config $"($config_path)/env.nu" ...$cmd -i } else { ^nu --config $"($config_path)/config.nu" --env-config $"($config_path)/env.nu" -i } } else { # Fallback if PROVISIONING_CONFIG not set if ($lib_paths | length) > 0 { let cmd = (mut cmd_parts = []; for path in $lib_paths { $cmd_parts = ($cmd_parts | append "-I" | append $path) }; $cmd_parts) ^nu ...$cmd -i } else { ^nu -i } } } else { # Also pass library paths for single command execution let lib_dirs = ($env.NU_LIB_DIRS? | default "") let lib_paths = if ($lib_dirs | is-not-empty) { ($lib_dirs | split row ":" | where { |x| ($x | is-not-empty) }) } else { [] } if ($lib_paths | length) > 0 { let cmd = (mut cmd_parts = []; for path in $lib_paths { $cmd_parts = ($cmd_parts | append "-I" | append $path) }; $cmd_parts) ^nu ...$cmd -c $"($run_ops)" } else { ^nu -c $"($run_ops)" } } } } # Nu info command handler - Show Nushell version info export def handle_nuinfo [] { print $"\n (_ansi yellow)Nu shell info(_ansi reset)" print (version) } # List command handler - List resources (servers, taskservs, clusters) export def handle_list [ops: string, flags: record] { let target_list = if ($ops | is-not-empty) { let parts = ($ops | split row " ") if ($parts | is-empty) { "" } else { $parts | first } } else { "" } let list_ops = ($ops | str replace $"($target_list) " "" | str trim) on_list $target_list ($flags.onsel | default "") $list_ops }