Final mega-batch of single-star conversions combined in one commit.
=== Orchestrator facades (Layer 3, expanded to explicit symbol lists) ===
config/accessor.nu 18 symbols (bridges accessor/mod)
config/accessor_generated.nu 18 symbols (consumer of accessor)
utils/version.nu 35 symbols (bridges version/mod)
dependencies/mod.nu 7 symbols from resolver.nu
oci_registry/mod.nu 12 multi-word "oci-registry X" subcommands
oci/commands.nu 12 symbols from oci/client.nu
+ removed redundant `use ./client.nu *` that
was duplicated below the selective import
=== Selective imports (Layer 2) ===
platform/discovery.nu target.nu [5 symbols]
platform/health.nu target.nu [2 symbols]
platform/connection.nu user/config [get-active-workspace]
vm/preparer.nu vm/detector [check-vm-capability]
vm/backend_libvirt.nu result.nu [7 symbols]
extensions/tests/test_versions.nu versions [5 symbols]
utils/version/loader.nu nickel_processor [ncl-eval ncl-eval-soft]
=== Dead imports dropped ===
platform/credentials.nu user/config
platform/activation.nu target
config/cache/core.nu cache/metadata
config/interpolation/core.nu helpers/environment
utils/version/loader.nu version/core (kept nickel_processor)
=== Also included (pre-existing edits from earlier session) ===
utils/settings.nu pilot selective imports — reformatted
(file was modified externally during session)
Validation: all 18 files match pre-existing baselines (0 errors for clean
ones; 4/18/24/45/50/50 for pre-existing transitive noise).
MILESTONE: 94.6% of star-imports eliminated (370 → 20).
Remaining 20 star-lines in 5 files are intentional:
- lib_provisioning/mod.nu (13 stars — root facade; empties in ADR-025 Phase 4)
- integrations/mod.nu (2 stars — re-exports already-selective children)
- cmd/environment.nu (3 stars — contains ~7 undefined function calls;
needs Blocker-1 style cleanup follow-up)
- providers/loader.nu (1 dynamic `use ($entry_point) *` — runtime dispatch)
- vm/cleanup_scheduler.nu (1 in string template — not a real import)
Refs: ADR-025
|
||
|---|---|---|
| .. | ||
| .gitkeep | ||
| cache | ||
| cfssl-install.sh | ||
| install_config.sh | ||
| install_nu.sh | ||
| module-loader | ||
| new_provisioning | ||
| old_provisioning | ||
| pack | ||
| port-manager | ||
| providers-install | ||
| provisioning | ||
| README.md | ||
| tools-install | ||
| tty-commands.conf | ||
| tty-dispatch.sh | ||
| tty-filter.sh | ||
Provisioning CLI - Flow-Aware TTY Command Management
Architecture Overview
The provisioning wrapper (provisioning/core/cli/provisioning) is a flow controller that manages three execution paths for command handling:
- Standalone TTY - Interactive commands that exit after execution
- Pipeline TTY - Interactive commands that output for piping to other commands
- Regular - Standard Nushell command processing
This design enables:
- Interactive commands (TTY input) without blocking Nushell
- Inter-command piping of TTY output to subsequent commands
- Same-command flow (TTY input → Nushell processing in one execution)
- Daemon optimization for non-interactive commands
How Flow Management Works
Execution Flow
User Command: provisioning <cmd> <args>
↓
Bash wrapper (provisioning)
↓
┌──────────────────────────────────────┐
│ Phase 1: TTY Command Detection │
│ - Read tty-commands.conf registry │
│ - Match command pattern │
└──────────────────────────────────────┘
↓
├─→ Not a TTY command → Continue to Nushell (normal processing)
│
└─→ TTY command found → Check flow type
↓
├─→ flow=exit → Execute wrapper, exit immediately
├─→ flow=pipe → Execute wrapper, output to stdout, exit (allows piping)
└─→ flow=continue → Execute wrapper, capture output, continue to Nushell
($env.TTY_OUTPUT available in Nushell)
Flow Types Explained
1. Standalone TTY Commands (flow=exit)
Use case: Interactive forms, setup wizards, authentication dialogs
Example: provisioning setup wizard
Flow:
Bash wrapper → TTY filter detects "setup wizard" → flow=exit
↓
Execute wrapper: core/shlib/setup-wizard-tty.sh
↓
User interaction (TypeDialog form)
↓
Exit wrapper → Exit bash wrapper
↓
Never reaches Nushell
Registry entry:
"setup wizard" "core/shlib/setup-wizard-tty.sh" "exit"
2. Pipeline TTY Commands (flow=pipe)
Use case: Getting user input to pipe to another command
Example: provisioning auth get-key | provisioning deploy --api-key-stdin
Flow:
Bash wrapper → TTY filter detects "auth get-key" → flow=pipe
↓
Execute wrapper: core/shlib/auth-get-key-tty.sh
↓
User provides API key via TTY prompt
↓
Wrapper outputs API key to stdout
↓
Exit wrapper (process exits, pipe has captured output)
↓
Next command receives API key from stdin
Registry entry:
"auth get-key" "core/shlib/auth-get-key-tty.sh" "pipe"
Wrapper requirements (flow=pipe):
- Must output result to stdout
- Output must be newline-terminated
- Exit with proper code (0=success, non-zero=error)
3. Continue-to-Nushell TTY Commands (flow=continue)
Use case: TTY input that needs further processing in Nushell
Example: provisioning auth integrate --provider azure
Flow:
Bash wrapper → TTY filter detects "auth integrate" → flow=continue
↓
Execute wrapper: core/shlib/auth-integrate-tty.sh
↓
User provides credentials via TTY prompt
↓
Wrapper outputs credentials (usually JSON) to stdout
↓
Filter CAPTURES output to $TTY_OUTPUT environment variable
↓
Set $env.PROVISIONING_BYPASS_DAEMON=true (skip daemon)
↓
Return 0 WITHOUT EXITING (continue to Nushell)
↓
Nushell dispatcher receives both:
- CLI args: --provider azure
- TTY output: $env.TTY_OUTPUT (credentials JSON)
↓
Nushell script processes both, completes integration
Registry entry:
"auth integrate" "core/shlib/auth-integrate-tty.sh" "continue"
Wrapper requirements (flow=continue):
- Must output result to stdout (usually JSON for structured data)
- Exit with proper code (0=success, non-zero=error)
Nushell script requirements (receives flow=continue output):
export def "provisioning auth integrate" [--provider: string] {
# Check if TTY output exists (guard pattern)
let tty_output = ($env.TTY_OUTPUT? | default "")
if ($tty_output | is-empty) {
error make {msg: "No credentials provided via TTY"}
}
# Parse TTY output (credentials)
let credentials = ($tty_output | from json)
# Use both TTY input ($credentials) and CLI args ($provider)
# Complete integration logic...
# Clear sensitive data after use
hide-env TTY_OUTPUT
}
4. Regular Commands
Use case: Standard provisioning operations
Example: provisioning server list
Flow:
Bash wrapper → TTY filter checks registry → Not found → Return 1
↓
Continue to normal processing:
- Fast-path checks (help, workspace, env, etc.)
- Daemon check (if applicable)
- Nushell dispatcher
Registry Format
File: provisioning/core/cli/tty-commands.conf
Three-field format: "PATTERN" "WRAPPER_PATH" "FLOW_TYPE"
# Exact command match (e.g., "setup wizard" matches "provisioning setup wizard")
"setup wizard" "core/shlib/setup-wizard-tty.sh" "exit"
# Paths are relative to $PROVISIONING
"auth get-key" "core/shlib/auth-get-key-tty.sh" "pipe"
# Flow types: exit | pipe | continue
"auth integrate" "core/shlib/auth-integrate-tty.sh" "continue"
Flow Type Decision Matrix
| Interaction | Flow Type | Example |
|---|---|---|
| Interactive form, no output needed | exit |
Setup wizard, auth login |
| User input → pipe to next command | pipe |
API key for piping to deploy |
| User input → same-command Nushell processing | continue |
Credentials for integration |
Adding New TTY Commands
Step 1: Create Wrapper Script
Create wrapper in provisioning/core/shlib/:
#!/bin/bash
set -euo pipefail
main() {
local input
# Get input from user
read -rsp "Prompt: " input
echo # Newline
# For flow=pipe: output to stdout
# For flow=continue: output to stdout (will be captured by filter)
echo "$input"
return 0
}
main "$@"
Make it executable:
chmod +x provisioning/core/shlib/your-wrapper-tty.sh
Step 2: Add Registry Entry
Edit provisioning/core/cli/tty-commands.conf:
# Standalone TTY
"your command" "core/shlib/your-wrapper-tty.sh" "exit"
# Pipeline TTY
"get something" "core/shlib/get-something-tty.sh" "pipe"
# Continue-to-Nushell TTY
"setup something" "core/shlib/setup-something-tty.sh" "continue"
Step 3: No Wrapper Modifications Required
The provisioning wrapper automatically:
- Reads registry
- Matches command pattern
- Routes based on flow type
- Handles all three flows
No need to modify provisioning wrapper for new commands!
Wrapper Script Requirements
For All Wrappers
- Shebang:
#!/bin/bash - Safety:
set -euo pipefail - Arguments: Accept
"${@}"from wrapper - Exit codes: 0=success, non-zero=error
- Validation:
shellcheckpasses without warnings
For flow=exit Wrappers
- Complete all interaction in wrapper
- Exit with proper code (0=success, non-zero=error)
- Output shown directly to user (from wrapper)
For flow=pipe Wrappers
- Get input from user (TTY)
- Output result to stdout
- Output must be newline-terminated
- Exit with proper code (0=success, non-zero=error)
For flow=continue Wrappers
- Get input from user (TTY)
- Output result to stdout (usually JSON)
- Exit with proper code (0=success, non-zero=error)
- Filter captures output → $TTY_OUTPUT
- Nushell script reads $env.TTY_OUTPUT
Environment Variables
Exported by Filter (flow=continue only)
$TTY_OUTPUT: Captured output from wrapper (available in Nushell as$env.TTY_OUTPUT)$PROVISIONING_BYPASS_DAEMON: Set to "true" to skip daemon (flow=continue automatically sets this)$TTY_WRAPPER_EXECUTED: Set to "true" when TTY wrapper was executed
Usage in Nushell
# Access TTY output in Nushell script
export def "provisioning auth integrate" [--provider: string] {
let tty_output = ($env.TTY_OUTPUT? | default "")
# Parse if JSON
let creds = ($tty_output | from json)
# Use both TTY output and CLI args
integration-logic $provider $creds
# Clear after use (security)
hide-env TTY_OUTPUT
}
Daemon Interaction
The flow filter intelligently manages daemon usage:
For flow=exit and flow=pipe
- ✅ Daemon can be used - No stdin required
- No output needs to be captured and passed to Nushell
- Daemon optimization available (~100ms startup improvement)
For flow=continue
- ❌ Daemon MUST be bypassed - stdin required for TTY interaction
PROVISIONING_BYPASS_DAEMON=trueautomatically set by filter- Direct Nushell execution (preserves stdin for TTY)
- Zero overhead (same as non-daemon path)
Testing TTY Commands
Test Standalone (flow=exit)
provisioning setup wizard
# Expected: TypeDialog form, user interaction, exits
Test Pipeline (flow=pipe)
provisioning auth get-key | wc -c
# Expected: Prompts for API key, outputs to pipe
Test Continue (flow=continue)
provisioning auth integrate --provider azure
# Expected: Prompts for credentials, passes to Nushell with $env.TTY_OUTPUT
Test Regular Command
provisioning server list
# Expected: Normal Nushell processing
Troubleshooting
Command Not Executed
- Check: Is command in tty-commands.conf?
- Check: Does pattern exactly match command?
- Check: Is wrapper path correct and executable?
Wrapper Not Found
- Error message:
Warning: TTY wrapper not found or not executable: /path/to/wrapper - Check: File exists at
$PROVISIONING/wrapper-path - Check: File is executable:
chmod +x wrapper-path
Output Not Piping (flow=pipe)
- Check: Wrapper outputs to stdout (not stderr)
- Check: Output is newline-terminated:
echo "output" - Check: No daemon interference (PROVISIONING_BYPASS_DAEMON not set)
Nushell Not Receiving Output (flow=continue)
- Check:
$env.TTY_OUTPUTaccessible in Nushell:echo $env.TTY_OUTPUT - Check: Output format (usually JSON):
echo $env.TTY_OUTPUT | from json - Check: Wrapper exits with 0:
echo $?
Implementation Details
Filter Location and Function
File: provisioning/core/cli/tty-filter.sh
Function: filter_tty_command()
Lines: ~104 (includes documentation and three flow paths)
Integration in Wrapper
File: provisioning/core/cli/provisioning
Lines: ~20 (sources filter, calls function, continues to Nushell)
Registry Parsing
- File:
provisioning/core/cli/tty-commands.conf - Method: Line-by-line bash read (no jq dependency)
- Format: Three-field bash array (bash-compatible)
- Sections: Organized by flow type for clarity
Performance Implications
startup time
- flow=exit/pipe: Daemon available for startup optimization (~100ms improvement)
- flow=continue: Daemon bypassed (stdin needed), ~500ms traditional path
- Regular commands: Normal daemon/non-daemon path selection
Memory
- flow=continue: Wrapper output stored in
$TTY_OUTPUTenvironment variable - Typical size: < 1KB (credentials, keys, etc.)
- Cleared after Nushell processing (or via
hide-env)
Security Considerations
Sensitive Data in $TTY_OUTPUT
- Credentials captured in
$TTY_OUTPUT - Nushell scripts should clear after use:
hide-env TTY_OUTPUT - Wrapper output may be logged: Use standard Unix conventions (hide passwords from output)
Wrapper Location Restriction
- Wrappers should be in
provisioning/core/shlib/orprovisioning/scripts/ - Registry reads only wrappers from these trusted locations
- Pattern validation prevents arbitrary script execution
No Shell Injection
- All variables quoted:
"$variable" - No eval or command substitution with user input
- Pattern matching uses exact string match (no regex)
Related Files
- Filter:
provisioning/core/cli/tty-filter.sh - Registry:
provisioning/core/cli/tty-commands.conf - Wrapper:
provisioning/core/cli/provisioning - Example wrappers:
provisioning/core/shlib/auth-get-key-tty.sh,provisioning/core/shlib/auth-integrate-tty.sh
Key Insights
The provisioning wrapper is not just a pass-through - it's a flow controller that:
- Detects TTY requirements (registry matching)
- Manages execution paths (three flows: exit, pipe, continue)
- Controls exit behavior (standalone vs pipeline vs same-command)
- Enables inter-command piping (TTY output to pipes)
- Supports Nushell integration (TTY→Nushell continuation)
- Optimizes with daemon (skip when stdin needed)
This solves:
- "el tema no es sólo un filter" → ✅ Flow controller with three execution paths
- "cómo gestionar el flow por medio del provisioning command" → ✅ Registry + flow types
- "usamos tty para input de una API key, se lo pasamos a un script de nushell" → ✅ Pipeline + continue flows
Version: 1.0.0 Last Updated: January 2026 Status: ✅ Production Ready