prvng_core/shlib/README.md

246 lines
8.3 KiB
Markdown
Raw Normal View History

# 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
2026-01-12 05:00:00 +00:00
┌─────────────────────────────────────────────────
────────────┐
│ User runs Nushell script │
2026-01-12 05:00:00 +00:00
└─────────────────┬───────────────────────────────
────────────┘
v
2026-01-12 05:00:00 +00:00
┌─────────────────────────────────────────────────
────────────┐
│ Nushell calls bash wrapper (shlib/*-tty.sh) │
2026-01-12 05:00:00 +00:00
└─────────────────┬───────────────────────────────
────────────┘
v
2026-01-12 05:00:00 +00:00
┌─────────────────────────────────────────────────
────────────┐
│ Bash wrapper handles TTY input (TypeDialog, prompts, etc) │
│ - Proper TTY file descriptor handling │
│ - Interactive input works correctly │
2026-01-12 05:00:00 +00:00
└─────────────────┬───────────────────────────────
────────────┘
v
2026-01-12 05:00:00 +00:00
┌─────────────────────────────────────────────────
────────────┐
│ Wrapper writes output to JSON file │
2026-01-12 05:00:00 +00:00
└─────────────────┬───────────────────────────────
────────────┘
v
2026-01-12 05:00:00 +00:00
┌─────────────────────────────────────────────────
────────────┐
│ Nushell reads JSON file (no TTY issues) │
│ - File-based IPC is reliable │
│ - No input stack problems │
2026-01-12 05:00:00 +00:00
└─────────────────────────────────────────────────
────────────┘
```
## 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