Merge _configs/ into config/ for single configuration directory. Update all path references. Changes: - Move _configs/* to config/ - Update .gitignore for new patterns - No code references to _configs/ found Impact: -1 root directory (layout_conventions.md compliance)
418 lines
11 KiB
Markdown
418 lines
11 KiB
Markdown
# Wrapper Script Design
|
|
|
|
Technical documentation for syntaxis wrapper scripts.
|
|
|
|
## Overview
|
|
|
|
Wrapper scripts are NuShell scripts created during installation that provide intelligent configuration discovery and environment setup for workspace binaries.
|
|
|
|
### Goals
|
|
|
|
1. **Automatic config discovery** - Find configuration files without user intervention
|
|
2. **Environment setup** - Set required environment variables before execution
|
|
3. **Transparency** - User sees no difference between wrapper and binary
|
|
4. **Flexibility** - Support multiple config file locations
|
|
5. **Debugging** - Easy to inspect what's happening
|
|
|
|
## Architecture
|
|
|
|
### Binary Layout After Installation
|
|
|
|
```
|
|
~/.cargo/bin/
|
|
├── workspace # Wrapper script (NuShell)
|
|
├── workspace.real # Actual binary (compiled executable)
|
|
├── syntaxis-tui # Wrapper script (NuShell)
|
|
├── syntaxis-tui.real # Actual binary (compiled executable)
|
|
└── syntaxis-dashboard # Actual binary (no wrapper, runs standalone)
|
|
```
|
|
|
|
### Wrapper Script Flow
|
|
|
|
```
|
|
User executes: workspace --help
|
|
↓
|
|
NuShell wrapper script (workspace)
|
|
↓
|
|
1. Search for config file in priority order
|
|
↓
|
|
2. If found: Set WORKSPACE_CONFIG_PATH
|
|
↓
|
|
3. Set other environment variables:
|
|
- WORKSPACE_CONFIG_DIR
|
|
- WORKSPACE_DATA_DIR
|
|
↓
|
|
4. Create data directory if needed
|
|
↓
|
|
5. Execute actual binary (workspace.real)
|
|
↓
|
|
Binary executes with environment setup
|
|
```
|
|
|
|
## Configuration Discovery
|
|
|
|
### Search Order
|
|
|
|
Wrapper scripts search for configuration files in this priority order:
|
|
|
|
```
|
|
1. ~/.config/core/workspace.toml
|
|
└─ User configuration
|
|
|
|
2. ~/.config/core/syntaxis-api.toml
|
|
└─ Fallback to main API config
|
|
|
|
3. .project/workspace.toml
|
|
└─ Project-specific configuration
|
|
|
|
4. .vapora/workspace.toml
|
|
└─ VAPORA-specific configuration
|
|
```
|
|
|
|
Returns first matching file, or `null` if none found.
|
|
|
|
### Configuration Discovery Logic
|
|
|
|
```nushell
|
|
let config_paths = [
|
|
$"($env.HOME)/.config/core/workspace.toml"
|
|
$"($env.HOME)/.config/core/syntaxis-api.toml"
|
|
".project/workspace.toml"
|
|
".vapora/workspace.toml"
|
|
]
|
|
|
|
let config_file = (
|
|
$config_paths
|
|
| where { |p| $p | path exists }
|
|
| first
|
|
)
|
|
```
|
|
|
|
This ensures:
|
|
- User configs are tried first
|
|
- Fallback to shared config if specific config not found
|
|
- Project configs override user configs
|
|
- VAPORA configs are respected
|
|
- If no config found, `config_file` is `null`
|
|
|
|
## Environment Variables
|
|
|
|
### Set by Wrapper
|
|
|
|
Wrapper scripts set these environment variables before execution:
|
|
|
|
| Variable | Purpose | Example |
|
|
|----------|---------|---------|
|
|
| `WORKSPACE_CONFIG_PATH` | Absolute path to found config file | `~/.config/core/workspace.toml` |
|
|
| `WORKSPACE_CONFIG_DIR` | Configuration directory | `~/.config/syntaxis` |
|
|
| `WORKSPACE_DATA_DIR` | Runtime data directory | `~/.local/share/syntaxis` |
|
|
|
|
### Read by Application
|
|
|
|
The workspace binary reads these variables:
|
|
|
|
```rust
|
|
// In Rust code
|
|
let config_path = std::env::var("WORKSPACE_CONFIG_PATH").ok();
|
|
let config_dir = std::env::var("WORKSPACE_CONFIG_DIR").ok();
|
|
let data_dir = std::env::var("WORKSPACE_DATA_DIR").ok();
|
|
```
|
|
|
|
The binary will:
|
|
1. Use `WORKSPACE_CONFIG_PATH` if set (from wrapper)
|
|
2. Search in `WORKSPACE_CONFIG_DIR` if set
|
|
3. Fall back to default locations if neither set
|
|
4. Create `WORKSPACE_DATA_DIR` if it doesn't exist
|
|
|
|
## Wrapper Script Implementation
|
|
|
|
### workspace wrapper script location
|
|
|
|
`~/.cargo/bin/workspace` (or wherever cargo/bin is)
|
|
|
|
### Full Wrapper Script Example
|
|
|
|
```nushell
|
|
#!/usr/bin/env nu
|
|
# Generated wrapper for workspace
|
|
# Automatically finds configuration and sets up environment
|
|
|
|
# Find configuration file in standard locations
|
|
let config_paths = [
|
|
$"($env.HOME)/.config/core/workspace.toml"
|
|
$"($env.HOME)/.config/core/syntaxis-api.toml"
|
|
".project/workspace.toml"
|
|
".vapora/workspace.toml"
|
|
]
|
|
|
|
let config_file = (
|
|
$config_paths
|
|
| where { |p| $p | path exists }
|
|
| first
|
|
)
|
|
|
|
# Setup environment variables
|
|
if ($config_file != null) {
|
|
$env.WORKSPACE_CONFIG_PATH = $config_file
|
|
}
|
|
|
|
$env.WORKSPACE_CONFIG_DIR = $"($env.HOME)/.config/syntaxis"
|
|
$env.WORKSPACE_DATA_DIR = $"($env.HOME)/.local/share/syntaxis"
|
|
|
|
# Create data directory if needed
|
|
^mkdir -p $env.WORKSPACE_DATA_DIR
|
|
|
|
# Call actual binary with all arguments
|
|
^~/.cargo/bin/workspace.real
|
|
```
|
|
|
|
### Key Design Decisions
|
|
|
|
1. **NuShell as wrapper language**
|
|
- Reason: Already used in project build system
|
|
- Advantage: Native path handling, string interpolation
|
|
- Consistency: All scripts use same language
|
|
|
|
2. **Search before setting variables**
|
|
- Reason: Only set `WORKSPACE_CONFIG_PATH` if config actually exists
|
|
- Advantage: Clear separation of concerns
|
|
- Benefit: Application can detect which config was used
|
|
|
|
3. **Always set `WORKSPACE_CONFIG_DIR` and `WORKSPACE_DATA_DIR`**
|
|
- Reason: Application needs these for fallback behavior
|
|
- Advantage: Consistent environment across all invocations
|
|
- Benefit: Predictable runtime behavior
|
|
|
|
4. **Create data directory automatically**
|
|
- Reason: Application might not have write permission to create
|
|
- Advantage: Fails fast if permission issues
|
|
- Benefit: Cleaner error messages
|
|
|
|
5. **Pass all arguments through**
|
|
- Reason: Transparent to user
|
|
- Advantage: No argument parsing needed in wrapper
|
|
- Method: Shell directly executes real binary (arguments auto-passed)
|
|
|
|
## Binary Renaming Strategy
|
|
|
|
### Why Rename?
|
|
|
|
Renaming actual binaries to `.real` suffix:
|
|
1. **Clarity** - Easy to see which files are wrappers vs. actual binaries
|
|
2. **Safety** - Prevents accidental execution of wrong file
|
|
3. **Maintenance** - Can easily identify wrapped binaries
|
|
4. **Reversibility** - Can restore by removing wrappers
|
|
|
|
### Renaming Process
|
|
|
|
```nushell
|
|
def create_wrappers [] {
|
|
let cargo_bin = ($env.HOME + "/.cargo/bin")
|
|
let binaries = ["workspace" "syntaxis-tui"]
|
|
|
|
for binary in $binaries {
|
|
let binary_path = ($cargo_bin + "/" + $binary)
|
|
let real_binary_path = ($cargo_bin + "/" + $binary + ".real")
|
|
|
|
if ($binary_path | path exists) {
|
|
^mv $binary_path $real_binary_path
|
|
# Now create wrapper script at original location
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Results:
|
|
```
|
|
Before: ~/.cargo/bin/workspace (executable binary)
|
|
After: ~/.cargo/bin/workspace.real (actual binary)
|
|
~/.cargo/bin/workspace (wrapper script)
|
|
```
|
|
|
|
## Installation Integration
|
|
|
|
### Creation During Installation
|
|
|
|
The `install_binary()` function:
|
|
1. Compiles binary with `cargo install`
|
|
2. Creates wrapper script via `create_wrapper_script()`
|
|
3. Renames binary to `.real` via `create_wrappers()`
|
|
4. Registers in manifest via `register_installations()`
|
|
|
|
### Manifest Tracking
|
|
|
|
Wrapper creation is tracked in `.syntaxis/manifest.toml`:
|
|
|
|
```toml
|
|
[binaries.workspace]
|
|
installed = true
|
|
wrapper = true # ← Indicates wrapper created
|
|
path = "~/.cargo/bin/workspace" # ← Wrapper location
|
|
real_binary = "~/.cargo/bin/workspace.real" # ← Real binary location
|
|
```
|
|
|
|
## Debugging Wrappers
|
|
|
|
### Inspect Wrapper Script
|
|
|
|
```bash
|
|
cat ~/.cargo/bin/workspace
|
|
```
|
|
|
|
Shows exact config discovery logic and environment setup.
|
|
|
|
### Trace Execution
|
|
|
|
Add debug output to see what's happening:
|
|
|
|
```nushell
|
|
# Modify wrapper to add debugging
|
|
let config_file = (
|
|
$config_paths
|
|
| where { |p| $p | path exists }
|
|
| first
|
|
)
|
|
|
|
print -e $"Found config: ($config_file)" # ← Add this line
|
|
print -e $"Config dir: ($env.WORKSPACE_CONFIG_DIR)"
|
|
print -e $"Data dir: ($env.WORKSPACE_DATA_DIR)"
|
|
|
|
^~/.cargo/bin/workspace.real
|
|
```
|
|
|
|
### Check Environment
|
|
|
|
```bash
|
|
# See what environment wrapper sets
|
|
strace -e execve ~/.cargo/bin/workspace --help 2>&1 | grep execve
|
|
|
|
# Or use nu debugging
|
|
nu -c 'source ~/.cargo/bin/workspace; print $env'
|
|
```
|
|
|
|
### Test Config Discovery
|
|
|
|
```bash
|
|
# Create test wrapper
|
|
cat > /tmp/test_wrapper.nu << 'EOF'
|
|
#!/usr/bin/env nu
|
|
|
|
let config_paths = [
|
|
$"($env.HOME)/.config/core/workspace.toml"
|
|
$"($env.HOME)/.config/core/syntaxis-api.toml"
|
|
".project/workspace.toml"
|
|
".vapora/workspace.toml"
|
|
]
|
|
|
|
let config_file = (
|
|
$config_paths
|
|
| where { |p| $p | path exists }
|
|
| first
|
|
)
|
|
|
|
print $"Found config: ($config_file)"
|
|
EOF
|
|
|
|
# Run test
|
|
nu /tmp/test_wrapper.nu
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
### Startup Overhead
|
|
|
|
Wrapper adds minimal overhead:
|
|
1. NuShell startup: ~10-50ms
|
|
2. Config search: ~0-5ms (depends on number of existing config files)
|
|
3. Directory creation: ~1-2ms
|
|
4. Total: ~15-60ms (negligible for CLI tools)
|
|
|
|
### Optimization Opportunities
|
|
|
|
If performance becomes critical:
|
|
|
|
1. **Cache config file location**
|
|
```nushell
|
|
# Store found path in environment for child processes
|
|
$env.WORKSPACE_CONFIG_FOUND = $config_file
|
|
```
|
|
|
|
2. **Short-circuit search**
|
|
```nushell
|
|
# Stop searching after first find
|
|
if ($"($env.HOME)/.config/core/workspace.toml" | path exists) {
|
|
# Use this, don't check others
|
|
}
|
|
```
|
|
|
|
3. **Skip directory creation**
|
|
```nushell
|
|
# Only create if needed (check first)
|
|
if not ($env.WORKSPACE_DATA_DIR | path exists) {
|
|
^mkdir -p $env.WORKSPACE_DATA_DIR
|
|
}
|
|
```
|
|
|
|
## Troubleshooting Guide
|
|
|
|
### Wrapper Not Found
|
|
|
|
**Problem**: `command not found: workspace`
|
|
|
|
**Solutions**:
|
|
1. Check PATH: `echo $PATH | grep .cargo/bin`
|
|
2. Verify installation: `ls -la ~/.cargo/bin/workspace*`
|
|
3. Check permissions: `ls -l ~/.cargo/bin/workspace`
|
|
4. Re-install: `just scripts-install workspace`
|
|
|
|
### Config Not Loading
|
|
|
|
**Problem**: Binary doesn't see configuration
|
|
|
|
**Solutions**:
|
|
1. Verify config exists: `ls ~/.config/core/workspace.toml`
|
|
2. Check wrapper sees it: `cat ~/.cargo/bin/workspace | grep config_paths`
|
|
3. Add debugging to wrapper (see Debugging section)
|
|
4. Check environment: `env | grep WORKSPACE`
|
|
|
|
### Permission Denied
|
|
|
|
**Problem**: `permission denied: ~/.cargo/bin/workspace`
|
|
|
|
**Solutions**:
|
|
1. Check permissions: `ls -l ~/.cargo/bin/workspace`
|
|
2. Make executable: `chmod +x ~/.cargo/bin/workspace`
|
|
3. Re-install: `just scripts-install workspace`
|
|
|
|
### Wrong Binary Executed
|
|
|
|
**Problem**: `.real` binary being called instead of wrapper
|
|
|
|
**Solutions**:
|
|
1. Check file order: `ls -la ~/.cargo/bin/workspace*`
|
|
2. Verify PATH order: `which workspace`
|
|
3. Clear PATH cache: `hash -r` (bash) or `rehash` (zsh)
|
|
4. Use full path: `~/.cargo/bin/workspace --help`
|
|
|
|
## Future Improvements
|
|
|
|
### Version 1.1
|
|
|
|
1. **Config file caching** - Cache found path to reduce startup time
|
|
2. **Wrapper updates** - Auto-update wrappers when configs change
|
|
3. **Enhanced debugging** - Built-in debug mode via `--debug` flag
|
|
4. **Config merging** - Merge multiple config files for inheritance
|
|
|
|
### Version 2.0
|
|
|
|
1. **Binary shims** - Replace NuShell wrappers with compiled shims (faster)
|
|
2. **Config templating** - Jinja2-style variable substitution in configs
|
|
3. **Hot reload** - Reload configs without restarting application
|
|
4. **Remote configs** - Load configs from remote servers
|
|
|
|
## Related Documentation
|
|
|
|
- **docs/installation-guide.md** - How to install wrappers
|
|
- **docs/configuration.md** - Configuration file options
|
|
- **scripts/install-cli.nu** - Wrapper creation implementation
|