prvng_core/forminquire/nulib/forminquire.nu
Jesús Pérez 85ce530733
feat: update provisioning core CLI, libraries, and plugins
Update core components including CLI, Nushell libraries, plugins system,
and utility scripts for the provisioning system.

CLI Updates:
- Command implementations
- CLI utilities and dispatching
- Help system improvements
- Command validation

Library Updates:
- Configuration management system
- Infrastructure validation
- Extension system improvements
- Secrets management
- Workspace operations
- Cache management system

Plugin System:
- Interactive form plugin (inquire)
- KCL integration plugin
- Performance optimization plugins
- Plugin registration system

Utilities:
- Build and distribution scripts
- Installation procedures
- Testing utilities
- Development tools

Documentation:
- Library module documentation
- Extension API guides
- Plugin usage guides
- Service management documentation

All changes are backward compatible. No breaking changes.
2025-12-11 21:57:05 +00:00

541 lines
16 KiB
Plaintext

#!/usr/bin/env nu
# [command]
# name = "forminquire integration"
# group = "infrastructure"
# tags = ["forminquire", "forms", "interactive", "templates"]
# version = "1.0.0"
# requires = ["nu_plugin_tera", "forminquire:1.0.0"]
# note = "Dynamic form generation using Jinja2 templates rendered with nu_plugin_tera"
# ============================================================================
# FormInquire Integration System
# Version: 1.0.0
# Purpose: Generate interactive forms dynamically from templates and config data
# ============================================================================
# Get form cache directory
def get-form-cache-dir [] : nothing -> string {
let cache_dir = (
if ($env.XDG_CACHE_HOME? | is-empty) {
$"($env.HOME)/.cache/provisioning/forms"
} else {
$"($env.XDG_CACHE_HOME)/provisioning/forms"
}
)
$cache_dir
}
# Ensure cache directory exists
def ensure-form-cache-dir [] : nothing -> string {
let cache_dir = (get-form-cache-dir)
let _mkdir_result = (do {
if not (($cache_dir | path exists)) {
^mkdir -p $cache_dir
}
} | complete)
$cache_dir
}
# Get template directory
def get-template-dir [] : nothing -> string {
let proj_root = (
if (($env.PROVISIONING_ROOT? | is-empty)) {
$"($env.HOME)/project-provisioning"
} else {
$env.PROVISIONING_ROOT
}
)
$"($proj_root)/provisioning/core/forminquire/templates"
}
# Load TOML configuration file
def load-toml-config [path: string] : nothing -> record {
let result = (do { open $path | from toml } | complete)
if ($result.exit_code == 0) {
$result.stdout
} else {
{}
}
}
# Load YAML configuration file
def load-yaml-config [path: string] : nothing -> record {
let result = (do { open $path | from yaml } | complete)
if ($result.exit_code == 0) {
$result.stdout
} else {
{}
}
}
# Render Jinja2 template with data
export def render-template [
template_name: string
data: record = {}
] : nothing -> record {
let template_dir = (get-template-dir)
let template_path = $"($template_dir)/($template_name).j2"
if not (($template_path | path exists)) {
return {
error: $"Template not found: ($template_path)"
content: ""
}
}
let template_content_result = (do { ^cat $template_path } | complete)
if ($template_content_result.exit_code != 0) {
return {
error: "Failed to read template file"
content: ""
}
}
let template_content = $template_content_result.stdout
let enriched_data = (
$data
| merge {
now_iso: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
home_dir: $env.HOME
username: (whoami)
provisioning_root: (
if (($env.PROVISIONING_ROOT? | is-empty)) {
$"($env.HOME)/project-provisioning"
} else {
$env.PROVISIONING_ROOT
}
)
}
)
let render_result = (do {
tera -t $template_content --data ($enriched_data | to json)
} | complete)
if ($render_result.exit_code == 0) {
{
error: ""
content: $render_result.stdout
}
} else {
{
error: "Template rendering failed"
content: ""
}
}
}
# Generate form from template and save to cache
export def generate-form [
form_name: string
template_name: string
data: record = {}
] : nothing -> record {
let cache_dir = (ensure-form-cache-dir)
let form_path = $"($cache_dir)/($form_name).toml"
let render_result = (render-template $template_name $data)
if not (($render_result.error | is-empty)) {
return {
success: false
error: $render_result.error
form_path: ""
}
}
let write_result = (do {
$render_result.content | ^tee $form_path > /dev/null
} | complete)
if ($write_result.exit_code == 0) {
{
success: true
error: ""
form_path: $form_path
}
} else {
{
success: false
error: "Failed to write form file"
form_path: ""
}
}
}
# Execute FormInquire with generated form
export def run-form [form_path: string] : nothing -> record {
if not (($form_path | path exists)) {
return {
success: false
error: $"Form file not found: ($form_path)"
values: {}
}
}
let forminquire_result = (do {
^forminquire --from-file $form_path --output json
} | complete)
if ($forminquire_result.exit_code != 0) {
return {
success: false
error: "FormInquire execution failed"
values: {}
}
}
let parse_result = (do {
$forminquire_result.stdout | from json
} | complete)
if ($parse_result.exit_code == 0) {
{
success: true
error: ""
values: $parse_result.stdout
}
} else {
{
success: false
error: "Failed to parse FormInquire output"
values: {}
}
}
}
# Complete flow: generate form from template and run it
export def interactive-form [
form_name: string
template_name: string
data: record = {}
] : nothing -> record {
let generate_result = (generate-form $form_name $template_name $data)
if not $generate_result.success {
return {
success: false
error: $generate_result.error
form_path: ""
values: {}
}
}
let run_result = (run-form $generate_result.form_path)
{
success: $run_result.success
error: $run_result.error
form_path: $generate_result.form_path
values: $run_result.values
}
}
# Load user preferences from config
export def load-user-preferences [] : nothing -> record {
let config_path = $"($env.HOME)/.config/provisioning/user_config.yaml"
load-yaml-config $config_path
}
# Load workspace config
export def load-workspace-config [workspace_name: string] : nothing -> record {
let workspace_dir = (
if (($env.PROVISIONING_WORKSPACE? | is-empty)) {
$"($env.HOME)/workspaces/($workspace_name)"
} else {
$env.PROVISIONING_WORKSPACE
}
)
let config_file = $"($workspace_dir)/config.toml"
load-toml-config $config_file
}
# Load system defaults
export def load-system-defaults [] : nothing -> record {
let proj_root = (
if (($env.PROVISIONING_ROOT? | is-empty)) {
$"($env.HOME)/project-provisioning"
} else {
$env.PROVISIONING_ROOT
}
)
let defaults_file = $"($proj_root)/provisioning/config/config.defaults.toml"
load-toml-config $defaults_file
}
# Merge multiple config sources with priority
export def merge-config-sources [
defaults: record = {}
workspace: record = {}
user: record = {}
overrides: record = {}
] : nothing -> record {
$defaults | merge $workspace | merge $user | merge $overrides
}
# Get form context with all available data
export def get-form-context [
workspace_name: string = ""
custom_data: record = {}
] : nothing -> record {
let defaults = (load-system-defaults)
let user_prefs = (load-user-preferences)
let workspace_config = (
if (($workspace_name | is-empty)) {
{}
} else {
load-workspace-config $workspace_name
}
)
let merged = (merge-config-sources $defaults $workspace_config $user_prefs $custom_data)
$merged
}
# Settings update form - loads current settings as defaults
export def settings-update-form [] : nothing -> record {
let context = (get-form-context)
let data = {
config_source: "system defaults + user preferences"
editor: ($context.preferences.editor? // "vim")
output_format: ($context.preferences.output_format? // "yaml")
default_log_level: ($context.preferences.default_log_level? // "info")
preferred_provider: ($context.preferences.preferred_provider? // "upcloud")
confirm_delete: ($context.preferences.confirm_delete? // true)
confirm_deploy: ($context.preferences.confirm_deploy? // true)
}
interactive-form "settings-update" "settings-update" $data
}
# Setup wizard form
export def setup-wizard-form [] : nothing -> record {
let context = (get-form-context)
let data = {
system_name: ($context.system_name? // "provisioning")
admin_email: ($context.admin_email? // "")
deployment_mode: ($context.deployment_mode? // "solo")
infrastructure_provider: ($context.infrastructure_provider? // "upcloud")
cpu_cores: ($context.resources.cpu_cores? // "4")
memory_gb: ($context.resources.memory_gb? // "8")
disk_gb: ($context.resources.disk_gb? // "50")
workspace_path: ($context.workspace_path? // $"($env.HOME)/provisioning-workspace")
}
interactive-form "setup-wizard" "setup-wizard" $data
}
# Workspace init form
export def workspace-init-form [workspace_name: string = ""] : nothing -> record {
let context = (get-form-context $workspace_name)
let data = {
workspace_name: (
if (($workspace_name | is-empty)) {
"default"
} else {
$workspace_name
}
)
workspace_description: ($context.description? // "")
workspace_path: ($context.path? // $"($env.HOME)/workspaces/($workspace_name)")
default_provider: ($context.default_provider? // "upcloud")
default_region: ($context.default_region? // "")
init_git: ($context.init_git? // true)
create_example_configs: ($context.create_example_configs? // true)
setup_secrets: ($context.setup_secrets? // true)
enable_testing: ($context.enable_testing? // true)
enable_monitoring: ($context.enable_monitoring? // false)
enable_orchestrator: ($context.enable_orchestrator? // true)
}
interactive-form "workspace-init" "workspace-init" $data
}
# Server delete confirmation form
export def server-delete-confirm-form [
server_name: string
server_ip: string = ""
server_status: string = ""
] : nothing -> record {
let data = {
server_name: $server_name
server_ip: $server_ip
server_status: $server_status
}
interactive-form "server-delete-confirm" "server-delete-confirm" $data
}
# Clean up old form files from cache (older than 1 day)
export def cleanup-form-cache [] : nothing -> record {
let cache_dir = (get-form-cache-dir)
if not (($cache_dir | path exists)) {
return {cleaned: 0, error: ""}
}
let find_result = (do {
^find $cache_dir -name "*.toml" -type f -mtime +1 -delete
} | complete)
{cleaned: 0, error: ""}
}
# List available templates
export def list-templates [] : nothing -> list {
let template_dir = (get-template-dir)
if not (($template_dir | path exists)) {
return []
}
let find_result = (do {
^find $template_dir -name "*.j2" -type f
} | complete)
if ($find_result.exit_code == 0) {
$find_result.stdout
| lines
| each {|path|
let name = ($path | path basename | str replace ".j2" "")
{
name: $name
path: $path
template_file: ($path | path basename)
}
}
} else {
[]
}
}
# List generated forms in cache
export def list-cached-forms [] : nothing -> list {
let cache_dir = (ensure-form-cache-dir)
let find_result = (do {
^find $cache_dir -name "*.toml" -type f
} | complete)
if ($find_result.exit_code == 0) {
$find_result.stdout
| lines
| each {|path|
{
name: ($path | path basename)
path: $path
}
}
} else {
[]
}
}
# ============================================================================
# DELETE CONFIRMATION HELPERS
# ============================================================================
# Run server delete confirmation
export def server-delete-confirm [
server_name: string
server_ip?: string
server_status?: string
] : nothing -> record {
let context = {
server_name: $server_name
server_ip: (if ($server_ip | is-empty) { "" } else { $server_ip })
server_status: (if ($server_status | is-empty) { "running" } else { $server_status })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/server_delete_confirm.toml" $context
}
# Run taskserv delete confirmation
export def taskserv-delete-confirm [
taskserv_name: string
taskserv_type?: string
taskserv_server?: string
taskserv_status?: string
dependent_services?: string
] : nothing -> record {
let context = {
taskserv_name: $taskserv_name
taskserv_type: (if ($taskserv_type | is-empty) { "" } else { $taskserv_type })
taskserv_server: (if ($taskserv_server | is-empty) { "" } else { $taskserv_server })
taskserv_status: (if ($taskserv_status | is-empty) { "unknown" } else { $taskserv_status })
dependent_services: (if ($dependent_services | is-empty) { "none" } else { $dependent_services })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/taskserv_delete_confirm.toml" $context
}
# Run cluster delete confirmation
export def cluster-delete-confirm [
cluster_name: string
cluster_type?: string
node_count?: string
total_resources?: string
deployments_count?: string
services_count?: string
volumes_count?: string
] : nothing -> record {
let context = {
cluster_name: $cluster_name
cluster_type: (if ($cluster_type | is-empty) { "" } else { $cluster_type })
node_count: (if ($node_count | is-empty) { "unknown" } else { $node_count })
total_resources: (if ($total_resources | is-empty) { "" } else { $total_resources })
deployments_count: (if ($deployments_count | is-empty) { "0" } else { $deployments_count })
services_count: (if ($services_count | is-empty) { "0" } else { $services_count })
volumes_count: (if ($volumes_count | is-empty) { "0" } else { $volumes_count })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/cluster_delete_confirm.toml" $context
}
# Generic delete confirmation
export def generic-delete-confirm [
resource_type: string
resource_name: string
resource_id?: string
resource_status?: string
] : nothing -> record {
let context = {
resource_type: $resource_type
resource_name: $resource_name
resource_id: (if ($resource_id | is-empty) { "" } else { $resource_id })
resource_status: (if ($resource_status | is-empty) { "unknown" } else { $resource_status })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/generic_delete_confirm.toml" $context
}
# Validate delete confirmation result
export def validate-delete-confirmation [result: record] : nothing -> bool {
# Must have success = true
let success = ($result.success // false)
if not $success {
return false
}
let values = ($result.values // {})
# Must have typed "DELETE" or "DELETE CLUSTER"
let confirm_text = ($values.confirmation_text // "")
let is_confirmed = (($confirm_text == "DELETE") or ($confirm_text == "DELETE CLUSTER"))
# Must have checked final confirmation checkbox
let final_checked = ($values.final_confirm // false)
# Must have checked proceed checkbox
let proceed_checked = ($values.proceed // false)
($is_confirmed and $final_checked and $proceed_checked)
}