# Shell Library (shlib) - TTY Wrappers **Purpose**: Bash wrappers that overcome Nushell's TTY input limitations in execution stacks. ## The Problem When Nushell scripts call interactive programs (like TypeDialog) within execution stacks, TTY input handling fails: ```nushell # This doesn't work properly in Nushell execution stacks: def run-interactive-form [] { let result = (^typedialog form input.toml) # TTY issues process_result $result } ``` **Why?** Nushell's pipeline and execution stack architecture doesn't properly forward TTY file descriptors to child processes in all contexts. ## The Solution **Bash wrappers** handle TTY input, then pass results to Nushell via files: ```text ┌─────────────────────────────────────────────────────────────┐ │ User runs Nushell script │ └─────────────────┬───────────────────────────────────────────┘ │ v ┌─────────────────────────────────────────────────────────────┐ │ Nushell calls bash wrapper (shlib/*-tty.sh) │ └─────────────────┬───────────────────────────────────────────┘ │ v ┌─────────────────────────────────────────────────────────────┐ │ Bash wrapper handles TTY input (TypeDialog, prompts, etc) │ │ - Proper TTY file descriptor handling │ │ - Interactive input works correctly │ └─────────────────┬───────────────────────────────────────────┘ │ v ┌─────────────────────────────────────────────────────────────┐ │ Wrapper writes output to JSON file │ └─────────────────┬───────────────────────────────────────────┘ │ v ┌─────────────────────────────────────────────────────────────┐ │ Nushell reads JSON file (no TTY issues) │ │ - File-based IPC is reliable │ │ - No input stack problems │ └─────────────────────────────────────────────────────────────┘ ``` ## Naming Convention Scripts in this directory follow the pattern: `{operation}-tty.sh` - **`{operation}`**: What the script does (e.g., `setup-wizard`, `auth-login`) - **`-tty`**: Indicates this is a TTY-handling wrapper - **`.sh`**: Bash script extension **Examples:** - `setup-wizard-tty.sh` - Setup wizard with TTY-safe input - `auth-login-tty.sh` - Authentication login with TTY-safe input - `mfa-enroll-tty.sh` - MFA enrollment with TTY-safe input ## Current Wrappers | Script | Purpose | TypeDialog Form | | ------ | ------- | --------------- | | `setup-wizard-tty.sh` | Initial system setup configuration | `.typedialog/core/forms/setup-wizard.toml` | | `auth-login-tty.sh` | User authentication login | `.typedialog/core/forms/auth-login.toml` | | `mfa-enroll-tty.sh` | Multi-factor authentication enrollment | `.typedialog/core/forms/mfa-enroll.toml` | ## Usage from Nushell ```nushell # Example: Run setup wizard from Nushell def run-setup-wizard-interactive [] { # Call bash wrapper (handles TTY properly) let wrapper = "provisioning/core/shlib/setup-wizard-tty.sh" let result = (bash $wrapper | complete) if $result.exit_code == 0 { # Read generated JSON (no TTY issues) let config = (open provisioning/.typedialog/core/generated/setup-wizard.json | from json) # Process config in Nushell process_config $config } else { print "Setup wizard failed" } } ``` ## Usage from Bash/CLI ```bash # Direct execution ./provisioning/core/shlib/setup-wizard-tty.sh # With environment variable (backend selection) TYPEDIALOG_BACKEND=web ./provisioning/core/shlib/auth-login-tty.sh # With custom output location OUTPUT_DIR=/tmp ./provisioning/core/shlib/mfa-enroll-tty.sh ``` ## Architecture Pattern All wrappers follow this pattern: 1. **Input Modes** (fallback chain): - TypeDialog interactive forms (if binary available) - Basic bash prompts (fallback) 2. **Output Format**: - Nickel config file (`.ncl`) - JSON export for Nushell (`.json`) 3. **File Locations**: - Forms: `provisioning/.typedialog/core/forms/` - Generated configs: `provisioning/.typedialog/core/generated/` - Templates: `provisioning/.typedialog/core/templates/` 4. **Error Handling**: - Exit code 0 = success - Exit code 1 = failure/cancelled - Stderr for error messages ## TypeDialog Integration These wrappers use TypeDialog forms when available: ```bash # TypeDialog form location FORM_PATH="provisioning/.typedialog/core/forms/setup-wizard.toml" # Run TypeDialog if command -v typedialog &> /dev/null; then typedialog form "$FORM_PATH" \ --output "$OUTPUT_NCL" \ --backend "${TYPEDIALOG_BACKEND:-tui}" # Export to JSON for Nushell nickel export --format json "$OUTPUT_NCL" > "$OUTPUT_JSON" fi ``` ## Fallback Behavior If TypeDialog is not available, wrappers fall back to basic prompts: ```bash # Fallback to basic bash prompts echo "TypeDialog not available. Using basic prompts..." read -p "Username: " username read -sp "Password: " password ``` This ensures the system always works, even without TypeDialog installed. ## When to Create a New Wrapper Create a new TTY wrapper when: 1. ✅ **Interactive input is required** (user must enter data) 2. ✅ **Called from Nushell context** (execution stack issues) 3. ✅ **TTY file descriptors matter** (TypeDialog, password prompts, etc.) Do NOT create a wrapper when: - ❌ Script is non-interactive (no user input) - ❌ Script only processes files (no TTY needed) - ❌ Script is already bash (no Nushell context) ## Troubleshooting ### Wrapper Not Found ```bash # Check wrapper exists and is executable ls -l provisioning/core/shlib/setup-wizard-tty.sh # Make executable if needed chmod +x provisioning/core/shlib/setup-wizard-tty.sh ``` ### TTY Input Still Fails ```bash # Ensure running from proper TTY tty # Should show /dev/ttys000 or similar # Check stdin is connected to TTY [ -t 0 ] && echo "stdin is TTY" || echo "stdin is NOT TTY" # Run wrapper directly (bypass Nushell) bash provisioning/core/shlib/setup-wizard-tty.sh ``` ### JSON Output Not Generated ```bash # Check TypeDialog and Nickel are installed command -v typedialog command -v nickel # Check output directory exists mkdir -p provisioning/.typedialog/core/generated # Check permissions ls -ld provisioning/.typedialog/core/generated ``` ## Related Documentation - **TypeDialog Forms**: `provisioning/.typedialog/core/forms/README.md` - **Nushell Integration**: `provisioning/core/nulib/lib_provisioning/setup/wizard.nu` - **Architecture Decision**: `docs/architecture/adr/ADR-XXX-tty-wrappers.md` ## Future Improvements Potential enhancements (when needed): 1. **Caching**: Store previous inputs for faster re-runs 2. **Validation**: Pre-validate inputs before calling TypeDialog 3. **Multi-backend**: Support web/tui/cli backends dynamically 4. **Batch mode**: Support non-interactive mode with config file input --- **Version**: 1.0.0 **Last Updated**: 2025-01-09 **Status**: Production Ready **Maintainer**: Provisioning Core Team