chore: forminquire full replace with typedialog and wrappers -tty.sh

This commit is contained in:
Jesús Pérez 2026-01-09 15:09:40 +00:00
parent d75a98b8cc
commit 700058b264
Signed by: jesus
GPG Key ID: 9F243E355E0BC939
13 changed files with 1338 additions and 14 deletions

182
.typedialog/README.md Normal file
View File

@ -0,0 +1,182 @@
# TypeDialog Configuration Structure
This directory contains TypeDialog forms, templates, and configuration data organized by subsystem.
## Directory Organization
```text
.typedialog/
├── core/ # Core subsystem forms (setup, auth, infrastructure)
├── provisioning/ # Main provisioning configuration fragments
└── platform/ # Platform services forms (future)
```
### Why Multiple Subdirectories
Different subsystems have different form requirements:
1. **`core/`** - Core infrastructure operations
- System setup wizard
- Authentication (login, MFA)
- Infrastructure confirmations (delete, deploy)
- **Users**: Developers, operators
2. **`provisioning/`** - Project provisioning configuration
- Deployment target selection (docker, k8s, ssh)
- Database configuration (postgres, mysql, sqlite)
- Monitoring setup
- **Users**: Project setup, CI/CD
3. **`platform/`** (future) - Platform services
- Orchestrator configuration
- Control center setup
- Service-specific forms
- **Users**: Platform administrators
## Structure Within Each Subdirectory
Each subdirectory follows this pattern:
```text
{subsystem}/
├── forms/ # TOML form definitions
├── templates/ # Nickel/Jinja2 templates
├── defaults/ # Default configurations
├── constraints/ # Validation rules
└── generated/ # Generated configs (gitignored)
```
## Core Subsystem (`core/`)
**Purpose**: Core infrastructure operations (setup, auth, confirmations)
**Forms**:
- `forms/setup-wizard.toml` - Initial system setup
- `forms/auth-login.toml` - User authentication
- `forms/mfa-enroll.toml` - MFA enrollment
- `forms/infrastructure/*.toml` - Delete confirmations (server, cluster, taskserv)
**Bash Wrappers** (TTY-safe):
- `../../core/shlib/setup-wizard-tty.sh`
- `../../core/shlib/auth-login-tty.sh`
- `../../core/shlib/mfa-enroll-tty.sh`
**Usage**:
```bash
# Run setup wizard
./provisioning/core/shlib/setup-wizard-tty.sh
# Nushell reads result
let config = (open provisioning/.typedialog/core/generated/setup-wizard-result.json | from json)
```
## Provisioning Subsystem (`provisioning/`)
**Purpose**: Main provisioning configuration (deployments, databases, monitoring)
**Structure**:
- `form.toml` - Main provisioning form
- `fragments/` - Modular form fragments
- `deployment-*.toml` - Docker, K8s, SSH deployments
- `database-*.toml` - Database configurations
- `monitoring.toml` - Monitoring setup
- `auth-*.toml` - Authentication methods
- `constraints.toml` - Validation constraints
- `defaults/` - Default values
- `schemas/` - Nickel schemas
**Usage**:
```bash
# Configure provisioning
nu provisioning/.typedialog/provisioning/configure.nu --backend web
```
## Platform Subsystem (`platform/` - Future)
**Purpose**: Platform services configuration
**Planned forms**:
- Orchestrator configuration
- Control center setup
- MCP server configuration
- Vault service setup
**Status**: Structure planned, not yet implemented
## Integration with Code
### Bash Wrappers (TTY-safe)
Located in: `provisioning/core/shlib/*-tty.sh`
These wrappers solve Nushell's TTY input limitations by:
1. Handling interactive input in bash
2. Calling TypeDialog with proper TTY forwarding
3. Generating JSON output for Nushell consumption
**Pattern**:
```text
Bash wrapper → TypeDialog (TTY input) → Nickel config → JSON → Nushell
```
### Nushell Integration
Located in: `provisioning/core/nulib/lib_provisioning/`
Functions that call the bash wrappers:
- `setup/wizard.nu::run-setup-wizard-interactive`
- `plugins/auth.nu::login-interactive`
- `plugins/auth.nu::mfa-enroll-interactive`
## Generated Files
**Location**: `{subsystem}/generated/`
**Files**:
- `*.ncl` - Nickel configuration files
- `*.json` - JSON exports for Nushell
- `*-defaults.ncl` - Default configurations
**Note**: All generated files are gitignored
## Form Naming Conventions
1. **Top-level forms**: `{purpose}.toml`
- Example: `setup-wizard.toml`, `auth-login.toml`
2. **Fragment forms**: `fragments/{category}-{variant}.toml`
- Example: `deployment-docker.toml`, `database-postgres.toml`
3. **Infrastructure forms**: `forms/infrastructure/{operation}_{resource}_confirm.toml`
- Example: `server_delete_confirm.toml`
## Adding New Forms
### For Core Operations
1. Create form: `.typedialog/core/forms/{operation}.toml`
2. Create wrapper: `core/shlib/{operation}-tty.sh`
3. Integrate in Nushell: `core/nulib/lib_provisioning/`
### For Provisioning Config
1. Create fragment: `.typedialog/provisioning/fragments/{category}-{variant}.toml`
2. Update main form: `.typedialog/provisioning/form.toml`
3. Add defaults: `.typedialog/provisioning/defaults/`
### For Platform Services (Future)
1. Create subsystem: `.typedialog/platform/`
2. Follow same structure as `core/` or `provisioning/`
3. Document in this README
## Related Documentation
- **Bash wrappers**: `provisioning/core/shlib/README.md`
- **TypeDialog integration**: `provisioning/platform/.typedialog/README.md`
- **Nushell setup**: `provisioning/core/nulib/lib_provisioning/setup/wizard.nu`
---
**Last Updated**: 2025-01-09
**Structure Version**: 2.0 (Multi-subsystem organization)

View File

@ -0,0 +1,89 @@
# Authentication Login Form
# Interactive login for provisioning system
# Location: .typedialog/provisioning/auth-login.toml
description = "Interactive authentication login"
display_mode = "complete"
locales_path = ""
name = "Authentication Login"
# ============================================================================
# LOGIN CREDENTIALS
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "login_header"
title = "🔐 Authentication Login"
type = "section_header"
[[elements]]
help = "Enter your username"
name = "username"
nickel_path = ["auth", "username"]
placeholder = "username"
prompt = "Username"
required = true
type = "text"
validation_pattern = "^[a-zA-Z0-9_-]+$"
[[elements]]
help = "Enter your password"
name = "password"
nickel_path = ["auth", "password"]
placeholder = "password"
prompt = "Password"
required = true
type = "password"
# ============================================================================
# MULTI-FACTOR AUTHENTICATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "mfa_header"
title = "🔒 Multi-Factor Authentication"
type = "section_header"
[[elements]]
help = "Do you have MFA enabled for this account?"
name = "has_mfa"
nickel_path = ["auth", "has_mfa"]
prompt = "MFA enabled?"
required = false
type = "confirm"
default = false
[[elements]]
help = "Enter your MFA code (6 digits)"
name = "mfa_code"
nickel_path = ["auth", "mfa_code"]
placeholder = "123456"
prompt = "MFA Code"
required = false
type = "text"
validation_pattern = "^[0-9]{6}$"
when = "has_mfa == true"
# ============================================================================
# CONFIRMATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "confirm_header"
title = "✅ Confirmation"
type = "section_header"
[[elements]]
help = "Confirm login with the provided credentials"
name = "confirm_login"
nickel_path = ["auth", "confirm_login"]
prompt = "Proceed with login?"
required = false
type = "confirm"
default = true

View File

@ -0,0 +1,116 @@
# Cluster Deletion Confirmation Form
# Generated: {{ now_iso }}
# Purpose: Confirm destructive cluster deletion operation
[meta]
title = "Cluster Deletion Confirmation"
description = "This action will permanently delete the entire cluster and all associated resources"
allow_cancel = true
# ============================================================================
# CRITICAL WARNING SECTION
# ============================================================================
[items.critical_warning]
type = "text"
prompt = "🔴 CRITICAL: Cluster Deletion is Irreversible"
display_only = true
[items.warning_details]
type = "text"
prompt = "Cluster Deletion will:"
help = """
Permanently delete all nodes in the cluster
Destroy all persistent volumes and data
Terminate all running applications and services
Remove all persistent configurations
Make cluster inaccessible - cannot be recovered"""
display_only = true
# ============================================================================
# CLUSTER INFORMATION
# ============================================================================
[items.cluster_info_header]
type = "text"
prompt = "Cluster to Delete"
display_only = true
[items.cluster_name]
type = "text"
prompt = "Cluster Name"
default = "{{ cluster_name | default('unknown') }}"
display_only = true
[items.cluster_type]
type = "text"
prompt = "Cluster Type"
default = "{{ cluster_type | default('unknown') }}"
display_only = true
[items.node_count]
type = "text"
prompt = "Number of Nodes"
default = "{{ node_count | default('unknown') }}"
display_only = true
[items.total_resources]
type = "text"
prompt = "Total Resources"
help = "Approximate total CPU and memory that will be freed"
default = "{{ total_resources | default('unknown') }}"
display_only = true
# ============================================================================
# DEPENDENT RESOURCES
# ============================================================================
[items.dependents_header]
type = "text"
prompt = "Resources That Will Be Deleted"
display_only = true
[items.deployments_count]
type = "text"
prompt = "Deployments"
default = "{{ deployments_count | default('0') }}"
display_only = true
[items.services_count]
type = "text"
prompt = "Services"
default = "{{ services_count | default('0') }}"
display_only = true
[items.volumes_count]
type = "text"
prompt = "Persistent Volumes"
default = "{{ volumes_count | default('0') }}"
display_only = true
# ============================================================================
# CONFIRMATION
# ============================================================================
[items.confirm_header]
type = "text"
prompt = "Final Confirmation Required"
display_only = true
[items.confirmation_text]
type = "text"
prompt = "Type 'DELETE CLUSTER' to Confirm"
help = "You must type the exact phrase: DELETE CLUSTER"
required = true
[items.understand_final]
type = "confirm"
prompt = "I understand this operation is permanent and all data will be lost"
help = "Check this box to acknowledge that you understand the consequences"
required = true
[items.proceed_final]
type = "confirm"
prompt = "Delete cluster '{{ cluster_name | default('cluster') }}' with {{ node_count | default('all') }} nodes?"
help = "This is the final confirmation. There is no undo."
required = true

View File

@ -0,0 +1,83 @@
# Generic Resource Deletion Confirmation Form
# Generated: {{ now_iso }}
# Purpose: Generic confirmation for any resource deletion
[meta]
title = "Resource Deletion Confirmation"
description = "Confirm permanent deletion of resource"
allow_cancel = true
# ============================================================================
# WARNING SECTION
# ============================================================================
[items.warning_header]
type = "text"
prompt = "⚠️ Warning: Permanent Deletion"
display_only = true
[items.resource_type]
type = "text"
prompt = "Resource Type"
default = "{{ resource_type | default('Resource') }}"
display_only = true
[items.resource_name]
type = "text"
prompt = "Resource Name"
default = "{{ resource_name | default('unknown') }}"
display_only = true
[items.resource_id]
type = "text"
prompt = "Resource ID"
help = "Unique identifier of the resource"
default = "{{ resource_id | default('') }}"
display_only = true
[items.resource_status]
type = "text"
prompt = "Current Status"
default = "{{ resource_status | default('unknown') }}"
display_only = true
# ============================================================================
# IMPACT INFORMATION
# ============================================================================
[items.impact_header]
type = "text"
prompt = "Deletion Impact"
display_only = true
[items.irreversible_warning]
type = "text"
prompt = "This action is irreversible"
help = "There is no way to undo this operation"
display_only = true
[items.data_loss_warning]
type = "text"
prompt = "All associated data will be permanently lost"
help = "This includes configurations, logs, and cached data"
display_only = true
# ============================================================================
# CONFIRMATION
# ============================================================================
[items.confirm_text]
type = "text"
prompt = "Type 'DELETE' to Confirm"
help = "This prevents accidental deletion"
required = true
[items.final_confirm]
type = "confirm"
prompt = "I understand this is permanent and all data will be lost"
required = true
[items.proceed]
type = "confirm"
prompt = "Delete {{ resource_type | default('resource') }} '{{ resource_name | default('unknown') }}'?"
required = true

View File

@ -0,0 +1,84 @@
# Server Deletion Confirmation Form
# Generated: {{ now_iso }}
# Purpose: Confirm destructive server deletion operation
[meta]
title = "Server Deletion Confirmation"
description = "This action will permanently delete the server and all associated data"
allow_cancel = true
# ============================================================================
# WARNING SECTION
# ============================================================================
[items.warning_header]
type = "text"
prompt = "⚠️ WARNING: This Action Cannot Be Undone"
display_only = true
[items.warning_text]
type = "text"
prompt = "Server Deletion will:"
help = """
Permanently remove the server from all providers
Delete all associated data and configurations
Terminate all running services
Release allocated IP addresses and storage"""
display_only = true
# ============================================================================
# SERVER INFORMATION
# ============================================================================
[items.server_info_header]
type = "text"
prompt = "Server to Delete"
display_only = true
[items.server_name]
type = "text"
prompt = "Server Name"
help = "Name of the server being deleted"
default = "{{ server_name | default('unknown') }}"
display_only = true
[items.server_ip]
type = "text"
prompt = "IP Address"
help = "Current IP address of the server"
default = "{{ server_ip | default('not assigned') }}"
display_only = true
[items.server_status]
type = "text"
prompt = "Current Status"
help = "Current operational status"
default = "{{ server_status | default('unknown') }}"
display_only = true
# ============================================================================
# CONFIRMATION
# ============================================================================
[items.confirm_header]
type = "text"
prompt = "Confirm Deletion"
display_only = true
[items.confirmation_text]
type = "text"
prompt = "Type 'DELETE' to Confirm"
help = "This prevents accidental deletion. You must type the exact word DELETE"
required = true
[items.final_confirm]
type = "confirm"
prompt = "I understand this is permanent and cannot be undone"
help = "Check this box to confirm you understand the consequences"
required = true
[items.proceed]
type = "confirm"
prompt = "Delete server {{ server_name | default('server') }}?"
help = "Final confirmation to proceed with deletion"
required = true

View File

@ -0,0 +1,108 @@
# Task Service Deletion Confirmation Form
# Generated: {{ now_iso }}
# Purpose: Confirm destructive taskserv deletion operation
[meta]
title = "Task Service Deletion Confirmation"
description = "This action will permanently delete the task service and all associated data"
allow_cancel = true
# ============================================================================
# WARNING SECTION
# ============================================================================
[items.warning_header]
type = "text"
prompt = "⚠️ WARNING: This Action Cannot Be Undone"
display_only = true
[items.warning_text]
type = "text"
prompt = "Task Service Deletion will:"
help = """
Permanently remove the service definition
Delete all containers and images
Remove all associated volumes and data
Terminate all running tasks
Invalidate all service references"""
display_only = true
# ============================================================================
# TASKSERV INFORMATION
# ============================================================================
[items.taskserv_info_header]
type = "text"
prompt = "Task Service to Delete"
display_only = true
[items.taskserv_name]
type = "text"
prompt = "Service Name"
help = "Name of the task service being deleted"
default = "{{ taskserv_name | default('unknown') }}"
display_only = true
[items.taskserv_type]
type = "text"
prompt = "Service Type"
help = "Type of service (e.g., kubernetes, postgres, redis)"
default = "{{ taskserv_type | default('unknown') }}"
display_only = true
[items.taskserv_server]
type = "text"
prompt = "Deployed On Server"
help = "Server hosting this task service"
default = "{{ taskserv_server | default('unknown') }}"
display_only = true
[items.taskserv_status]
type = "text"
prompt = "Current Status"
help = "Operational status of the service"
default = "{{ taskserv_status | default('unknown') }}"
display_only = true
# ============================================================================
# IMPACT ANALYSIS
# ============================================================================
[items.impact_header]
type = "text"
prompt = "Services That Depend on This"
display_only = true
[items.dependent_services]
type = "text"
prompt = "Dependent Services"
help = "These services will be affected by deletion"
default = "{{ dependent_services | default('none') }}"
display_only = true
# ============================================================================
# CONFIRMATION
# ============================================================================
[items.confirm_header]
type = "text"
prompt = "Confirm Deletion"
display_only = true
[items.confirmation_text]
type = "text"
prompt = "Type 'DELETE' to Confirm"
help = "This prevents accidental deletion. You must type the exact word DELETE"
required = true
[items.final_confirm]
type = "confirm"
prompt = "I understand this is permanent and will affect dependent services"
help = "Check this box to confirm you understand the consequences"
required = true
[items.proceed]
type = "confirm"
prompt = "Delete {{ taskserv_type | default('task service') }} '{{ taskserv_name | default('unknown') }}'?"
help = "Final confirmation to proceed with deletion"
required = true

View File

@ -0,0 +1,172 @@
# MFA Enrollment Form
# Interactive Multi-Factor Authentication enrollment
# Location: .typedialog/provisioning/mfa-enroll.toml
description = "Interactive Multi-Factor Authentication enrollment"
display_mode = "complete"
locales_path = ""
name = "MFA Enrollment"
# ============================================================================
# MFA CONFIGURATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "mfa_header"
title = "🔐 Multi-Factor Authentication Setup"
type = "section_header"
[[elements]]
help = "Choose the MFA method"
name = "mfa_type"
nickel_path = ["mfa", "type"]
prompt = "MFA Type"
required = true
type = "select"
options = ["totp", "webauthn", "sms"]
default = "totp"
# ============================================================================
# TOTP CONFIGURATION (Time-based One-Time Password)
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "totp_header"
title = "📱 TOTP Configuration"
type = "section_header"
when = "mfa_type == 'totp'"
[[elements]]
help = "Name for this MFA device (e.g., 'iPhone', 'Authenticator App')"
name = "totp_device_name"
nickel_path = ["mfa", "totp", "device_name"]
placeholder = "My Phone"
prompt = "Device name"
required = false
type = "text"
default = "Authenticator App"
when = "mfa_type == 'totp'"
[[elements]]
help = "Verify your setup by entering the code from your authenticator app"
name = "totp_verification_code"
nickel_path = ["mfa", "totp", "verification_code"]
placeholder = "123456"
prompt = "Verification code (6 digits)"
required = false
type = "text"
validation_pattern = "^[0-9]{6}$"
when = "mfa_type == 'totp'"
# ============================================================================
# WEBAUTHN CONFIGURATION (Hardware Keys / Biometrics)
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "webauthn_header"
title = "🔑 WebAuthn Configuration"
type = "section_header"
when = "mfa_type == 'webauthn'"
[[elements]]
help = "Name for this security key (e.g., 'YubiKey', 'Fingerprint')"
name = "webauthn_device_name"
nickel_path = ["mfa", "webauthn", "device_name"]
placeholder = "Security Key"
prompt = "Device name"
required = false
type = "text"
default = "Security Key"
when = "mfa_type == 'webauthn'"
# ============================================================================
# SMS CONFIGURATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "sms_header"
title = "📲 SMS Configuration"
type = "section_header"
when = "mfa_type == 'sms'"
[[elements]]
help = "Phone number for SMS verification (international format: +1234567890)"
name = "sms_phone_number"
nickel_path = ["mfa", "sms", "phone_number"]
placeholder = "+1234567890"
prompt = "Phone number"
required = false
type = "text"
validation_pattern = "^\\+[0-9]{10,15}$"
when = "mfa_type == 'sms'"
[[elements]]
help = "Verify your phone number by entering the SMS code"
name = "sms_verification_code"
nickel_path = ["mfa", "sms", "verification_code"]
placeholder = "123456"
prompt = "SMS verification code (6 digits)"
required = false
type = "text"
validation_pattern = "^[0-9]{6}$"
when = "mfa_type == 'sms'"
# ============================================================================
# BACKUP CODES
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "backup_header"
title = "💾 Backup Codes"
type = "section_header"
[[elements]]
help = "Generate backup codes for account recovery"
name = "generate_backup_codes"
nickel_path = ["mfa", "generate_backup_codes"]
prompt = "Generate backup codes?"
required = false
type = "confirm"
default = true
[[elements]]
help = "Number of backup codes to generate"
name = "backup_codes_count"
nickel_path = ["mfa", "backup_codes_count"]
prompt = "Number of backup codes"
required = false
type = "number"
min = 5
max = 20
default = 10
when = "generate_backup_codes == true"
# ============================================================================
# CONFIRMATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "confirm_header"
title = "✅ Confirmation"
type = "section_header"
[[elements]]
help = "Confirm MFA enrollment with the provided configuration"
name = "confirm_enroll"
nickel_path = ["mfa", "confirm_enroll"]
prompt = "Complete MFA enrollment?"
required = false
type = "confirm"
default = true

View File

@ -0,0 +1,222 @@
# Setup Wizard Form for Provisioning System
# Interactive configuration for initial system setup
# Location: .typedialog/provisioning/setup-wizard.toml
description = "Interactive setup wizard for provisioning system initialization"
display_mode = "complete"
locales_path = ""
name = "Provisioning System Setup Wizard"
# ============================================================================
# SYSTEM CONFIGURATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "system_header"
title = "⚙️ System Configuration"
type = "section_header"
[[elements]]
help = "Base path for storing configuration files"
name = "config_path"
nickel_path = ["system_config", "config_path"]
placeholder = "/Users/username/.config/provisioning"
prompt = "Configuration base path"
required = true
type = "text"
[[elements]]
help = "Use recommended paths for your operating system"
name = "use_defaults"
nickel_path = ["system_config", "use_defaults"]
prompt = "Use recommended paths for your OS?"
required = false
type = "confirm"
default = true
# ============================================================================
# DEPLOYMENT MODE SELECTION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "deployment_header"
title = "🚀 Deployment Mode"
type = "section_header"
[[elements]]
help = "Choose how platform services will be deployed"
name = "deployment_mode"
nickel_path = ["deployment_mode"]
prompt = "Deployment mode"
required = true
type = "select"
options = ["docker-compose", "kubernetes", "remote-ssh", "systemd"]
default = "docker-compose"
# ============================================================================
# PROVIDER SELECTION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "providers_header"
title = "☁️ Infrastructure Providers"
type = "section_header"
[[elements]]
help = "Select which infrastructure providers to enable"
name = "providers_info"
title = "Select at least one provider"
type = "section_header"
[[elements]]
help = "Enable UpCloud provider"
name = "provider_upcloud"
nickel_path = ["providers", "upcloud"]
prompt = "Use UpCloud?"
required = false
type = "confirm"
default = false
[[elements]]
help = "Enable AWS provider"
name = "provider_aws"
nickel_path = ["providers", "aws"]
prompt = "Use AWS?"
required = false
type = "confirm"
default = false
[[elements]]
help = "Enable Hetzner provider"
name = "provider_hetzner"
nickel_path = ["providers", "hetzner"]
prompt = "Use Hetzner?"
required = false
type = "confirm"
default = false
[[elements]]
help = "Enable local provider (required for local deployments)"
name = "provider_local"
nickel_path = ["providers", "local"]
prompt = "Use local provider?"
required = false
type = "confirm"
default = true
# ============================================================================
# RESOURCE ALLOCATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "resources_header"
title = "💻 Resource Allocation"
type = "section_header"
[[elements]]
help = "Number of CPU cores to allocate"
name = "cpu_count"
nickel_path = ["resources", "cpu_count"]
prompt = "Number of CPUs to allocate"
required = true
type = "number"
min = 1
max = 128
default = 4
[[elements]]
help = "Amount of memory to allocate (in GB)"
name = "memory_gb"
nickel_path = ["resources", "memory_gb"]
prompt = "Memory in GB to allocate"
required = true
type = "number"
min = 1
max = 1024
default = 8
# ============================================================================
# SECURITY CONFIGURATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "security_header"
title = "🔒 Security Configuration"
type = "section_header"
[[elements]]
help = "Enable Multi-Factor Authentication for enhanced security"
name = "enable_mfa"
nickel_path = ["security", "enable_mfa"]
prompt = "Enable Multi-Factor Authentication (MFA)?"
required = false
type = "confirm"
default = true
[[elements]]
help = "Enable audit logging for all operations"
name = "enable_audit"
nickel_path = ["security", "enable_audit"]
prompt = "Enable audit logging for all operations?"
required = false
type = "confirm"
default = true
[[elements]]
help = "Require approval for destructive operations"
name = "require_approval"
nickel_path = ["security", "require_approval_for_destructive"]
prompt = "Require approval for destructive operations?"
required = false
type = "confirm"
default = true
# ============================================================================
# WORKSPACE CONFIGURATION
# ============================================================================
[[elements]]
border_bottom = true
border_top = true
name = "workspace_header"
title = "📁 Initial Workspace"
type = "section_header"
[[elements]]
help = "Create an initial workspace for your infrastructure"
name = "create_workspace"
nickel_path = ["workspace", "create_workspace"]
prompt = "Create workspace now?"
required = false
type = "confirm"
default = true
[[elements]]
help = "Name for the initial workspace"
name = "workspace_name"
nickel_path = ["workspace", "name"]
prompt = "Workspace name"
required = false
type = "text"
default = "default"
when = "create_workspace == true"
[[elements]]
help = "Optional description for the workspace"
name = "workspace_description"
nickel_path = ["workspace", "description"]
prompt = "Workspace description (optional)"
required = false
type = "text"
default = "Default workspace"
when = "create_workspace == true"

2
core

@ -1 +1 @@
Subproject commit a327f59bf739f040b313f3b4b6b7d89972335b60
Subproject commit 6c46596cb3cfc19b5df7ca1118cf734cfd3638b4

View File

@ -33,6 +33,7 @@
- [Database and Config Architecture](architecture/database-and-config-architecture.md)
- [Ecosystem Integration](architecture/ecosystem-integration.md)
- [Package and Loader System](architecture/package-and-loader-system.md)
- [Config Loading Architecture](architecture/config-loading-architecture.md)
- [Nickel Executable Examples](architecture/nickel-executable-examples.md)
- [Orchestrator Info](architecture/orchestrator_info.md)
- [Orchestrator Auth Integration](architecture/orchestrator-auth-integration.md)

View File

@ -0,0 +1,266 @@
# Modular Configuration Loading Architecture
## Overview
The configuration system has been refactored into modular components to achieve 2-3x performance improvements
for regular commands while maintaining full functionality for complex operations.
## Architecture Layers
### Layer 1: Minimal Loader (0.023s)
**File**: `loader-minimal.nu` (~150 lines)
Contains only essential functions needed for:
- Workspace detection
- Environment determination
- Project root discovery
- Fast path detection
**Exported Functions**:
- `get-active-workspace` - Get current workspace
- `detect-current-environment` - Determine dev/test/prod
- `get-project-root` - Find project directory
- `get-defaults-config-path` - Path to default config
- `check-if-sops-encrypted` - SOPS file detection
- `find-sops-config-path` - Locate SOPS config
**Used by**:
- Help commands (help infrastructure, help workspace, etc.)
- Status commands
- Workspace listing
- Quick reference operations
### Layer 2: Lazy Loader (decision layer)
**File**: `loader-lazy.nu` (~80 lines)
Smart loader that decides which configuration to load:
- Fast path for help/status commands
- Full path for operations that need config
**Key Function**:
- `command-needs-full-config` - Determines if full config required
### Layer 3: Full Loader (0.091s)
**File**: `loader.nu` (1990 lines)
Original comprehensive loader that handles:
- Hierarchical config loading
- Variable interpolation
- Config validation
- Provider configuration
- Platform configuration
**Used by**:
- Server creation
- Infrastructure operations
- Deployment commands
- Anything needing full config
## Performance Characteristics
### Benchmarks
| Operation | Time | Notes |
| --------- | ---- | ----- |
| Workspace detection | 0.023s | 23ms for minimal load |
| Full config load | 0.091s | ~4x slower than minimal |
| Help command | 0.040s | Uses minimal loader only |
| Status command | 0.030s | Fast path, no full config |
| Server operations | 0.150s+ | Requires full config load |
### Performance Gains
- **Help commands**: 30-40% faster (40ms vs 60ms with full config)
- **Workspace operations**: 50% faster (uses minimal loader)
- **Status checks**: Nearly instant (23ms)
## Module Dependency Graph
```plaintext
Help/Status Commands
loader-lazy.nu
loader-minimal.nu (workspace, environment detection)
(no further deps)
Infrastructure/Server Commands
loader-lazy.nu
loader.nu (full configuration)
├── loader-minimal.nu (for workspace detection)
├── Interpolation functions
├── Validation functions
└── Config merging logic
```plaintext
## Usage Examples
### Fast Path (Help Commands)
```nushell
# Uses minimal loader - 23ms
./provisioning help infrastructure
./provisioning workspace list
./provisioning version
```plaintext
### Medium Path (Status Operations)
```nushell
# Uses minimal loader with some full config - ~50ms
./provisioning status
./provisioning workspace active
./provisioning config validate
```plaintext
### Full Path (Infrastructure Operations)
```nushell
# Uses full loader - ~150ms
./provisioning server create --infra myinfra
./provisioning taskserv create kubernetes
./provisioning workflow submit batch.yaml
```plaintext
## Implementation Details
### Lazy Loading Decision Logic
```nushell
# In loader-lazy.nu
let is_fast_command = (
$command == "help" or
$command == "status" or
$command == "version"
)
if $is_fast_command {
# Use minimal loader only (0.023s)
get-minimal-config
} else {
# Load full configuration (0.091s)
load-provisioning-config
}
```plaintext
### Minimal Config Structure
The minimal loader returns a lightweight config record:
```nushell
{
workspace: {
name: "librecloud"
path: "/path/to/workspace_librecloud"
}
environment: "dev"
debug: false
paths: {
base: "/path/to/workspace_librecloud"
}
}
```plaintext
This is sufficient for:
- Workspace identification
- Environment determination
- Path resolution
- Help text generation
### Full Config Structure
The full loader returns comprehensive configuration with:
- Workspace settings
- Provider configurations
- Platform settings
- Interpolated variables
- Validation results
- Environment-specific overrides
## Migration Path
### For CLI Commands
1. Commands are already categorized (help, workspace, server, etc.)
2. Help system uses fast path (minimal loader)
3. Infrastructure commands use full path (full loader)
4. No changes needed to command implementations
### For New Modules
When creating new modules:
1. Check if full config is needed
2. If not, use `loader-minimal.nu` functions only
3. If yes, use `get-config` from main config accessor
## Future Optimizations
### Phase 2: Per-Command Config Caching
- Cache full config for 60 seconds
- Reuse config across related commands
- Potential: Additional 50% improvement
### Phase 3: Configuration Profiles
- Create thin config profiles for common scenarios
- Pre-loaded templates for workspace/infra combinations
- Fast switching between profiles
### Phase 4: Parallel Config Loading
- Load workspace and provider configs in parallel
- Async validation and interpolation
- Potential: 30% improvement for full config load
## Maintenance Notes
### Adding New Functions to Minimal Loader
Only add if:
1. Used by help/status commands
2. Doesn't require full config
3. Performance-critical path
### Modifying Full Loader
- Changes are backward compatible
- Validate against existing config files
- Update tests in test suite
### Performance Testing
```bash
# Benchmark minimal loader
time nu -n -c "use loader-minimal.nu *; get-active-workspace"
# Benchmark full loader
time nu -c "use config/accessor.nu *; get-config"
# Benchmark help command
time ./provisioning help infrastructure
```plaintext
## See Also
- `loader.nu` - Full configuration loading system
- `loader-minimal.nu` - Fast path loader
- `loader-lazy.nu` - Smart loader decision logic
- `config/ARCHITECTURE.md` - Configuration architecture details

View File

@ -308,8 +308,8 @@ provisioning/platform/scripts/
| **Generation Scripts** | ✅ Complete | Auto-generate configs for all modes |
| **Validation Scripts** | ✅ Complete | Validate Docker, K8s, Nginx, Prometheus |
| **Platform Config** | ✅ Complete | 36 TOML files in runtime/generated/ |
| **TypeDialog Ready** | ✅ Ready | Structure prepared, awaiting binary |
| **FormInquire** | ✅ Active | Alternative setup wizard functional |
| **TypeDialog Forms** | ✅ Ready | Forms + bash wrappers created, awaiting binary |
| **Setup Wizard** | ✅ Active | Basic prompts as fallback |
| **Documentation** | ✅ Complete | All guides updated with examples |
---
@ -319,14 +319,15 @@ provisioning/platform/scripts/
### Now Available
- Generate infrastructure configs for solo/enterprise modes
- Validate generated configs with format-specific tools
- Use interactive setup wizard with FormInquire
- Use interactive setup wizard with basic Nushell prompts
- TypeDialog forms created and ready (awaiting binary install)
- Deploy with Docker/Kubernetes using generated configs
### When TypeDialog Becomes Available
### When TypeDialog Binary Becomes Available
- Install TypeDialog binary
- Auto-generate forms from infrastructure schemas
- Use form-based configuration for all services
- Upgrade setup wizard to TypeDialog
- TypeDialog forms already created (setup, auth, MFA)
- Bash wrappers handle TTY input (no Nushell stack issues)
- Full nickel-roundtrip workflow will be enabled
---

View File

@ -62,7 +62,7 @@
slow_operation = true,
rust_optimizable = false,
},
form_path = "provisioning/core/shlib/forms/infrastructure/server_delete_confirm.toml",
form_path = "provisioning/.typedialog/core/forms/infrastructure/server_delete_confirm.toml",
estimated_time = 60,
},
@ -123,7 +123,7 @@
slow_operation = true,
rust_optimizable = false,
},
form_path = "provisioning/core/shlib/forms/infrastructure/taskserv_delete_confirm.toml",
form_path = "provisioning/.typedialog/core/forms/infrastructure/taskserv_delete_confirm.toml",
estimated_time = 60,
},
@ -165,7 +165,7 @@
slow_operation = false,
rust_optimizable = false,
},
form_path = "provisioning/core/forminquire/templates/workspace-init.form.j2",
form_path = "provisioning/.typedialog/core/forms/setup-wizard.toml",
estimated_time = 30,
},
@ -227,7 +227,7 @@
slow_operation = false,
rust_optimizable = false,
},
form_path = "provisioning/core/shlib/forms/authentication/auth_login.toml",
form_path = "provisioning/.typedialog/core/forms/auth-login.toml",
estimated_time = 2,
},
@ -248,7 +248,7 @@
slow_operation = false,
rust_optimizable = false,
},
form_path = "provisioning/core/shlib/forms/authentication/mfa_enroll.toml",
form_path = "provisioning/.typedialog/core/forms/mfa-enroll.toml",
estimated_time = 30,
},
@ -270,7 +270,7 @@
slow_operation = false,
rust_optimizable = false,
},
form_path = "provisioning/core/forminquire/templates/setup-wizard.form.j2",
form_path = "provisioning/.typedialog/core/forms/setup-wizard.toml",
estimated_time = 120,
},