# ADR-002: Bundle Wrapper Deployment Architecture

**Date**: 2025-11-17
**Status**: ACCEPTED
**Version**: 2.0 (Updated with hybrid NuShell + Bash fallback)
**Author**: Architecture Review
**Scope**: Hybrid runtime wrapper deployment for bundle installations

---

## Problem Statement

**Question**: Should bundle installations create the same three-layer wrapper structure that development installations create?

**Current State**:
- **Development users** (`scripts/install-syntaxis.nu`): Get full wrapper infrastructure
  - Binaries renamed to `.real`
  - Bash wrappers at original locations
  - NuShell wrappers deployed to `~/.config/syntaxis/scripts/`
  - Result: Auto-config injection ✅ → Users type: `syntaxis-cli status`

- **Bundle users** (`scripts/provisioning/install.sh`): Get direct binaries only
  - Binaries installed directly
  - No wrapper infrastructure
  - No config auto-injection
  - Result: Manual config flags ❌ → Users must type: `syntaxis-cli --config path status`

**The Issue**: Inconsistent user experience between installation methods.

---

## Wrapper Architecture: Hybrid Design (NuShell + Bash Fallback)

### With NuShell Installed (Preferred): Three Layers

**Layer 1: Bash Wrapper**
```bash
~/.local/bin/syntaxis-cli  (300 bytes)
  ├─ Checks: Is NuShell available?
  ├─ If YES: Sets NU_LIB_DIRS="$HOME/.config/syntaxis/scripts"
  └─ Calls: nu "$HOME/.config/syntaxis/scripts/syntaxis-cli.nu" "$@"
```

**Layer 2: NuShell Wrapper**
```nushell
~/.config/syntaxis/scripts/syntaxis-cli.nu  (2.2 KB)
  ├─ Searches: Config file locations
  ├─ Discovers: ~/.config/syntaxis/syntaxis-cli.toml
  ├─ Injects: --config ~/.config/syntaxis/syntaxis-cli.toml
  └─ Calls: ~/.local/bin/syntaxis-cli.real --config ... status
```

**Layer 3: Real Binary**
```
~/.local/bin/syntaxis-cli.real  (7.2 MB)
  └─ Actual compiled Rust binary
```

### Without NuShell: Two Layers (Simplified)

**Layer 1: Bash Wrapper (with inline config discovery)**
```bash
~/.local/bin/syntaxis-cli  (300 bytes)
  ├─ Checks: Is NuShell available?
  ├─ If NO: Use bash-only config discovery
  ├─ Searches: Config in ~/.config/syntaxis/*, .syntaxis/, .project/, .coder/
  ├─ If found: Injects --config flag
  └─ Calls: ~/.local/bin/syntaxis-cli.real --config <found> status
```

**Layer 2: Real Binary**
```
~/.local/bin/syntaxis-cli.real  (7.2 MB)
  └─ Actual compiled Rust binary
```

### User Experience
```bash
$ syntaxis-cli status
# Wrapper automatically injects --config
# Clean, simple, no typing burden
```

---

## Decision: ADD HYBRID WRAPPERS TO BUNDLE

**Recommendation**: Bundle installations should create hybrid wrappers that work with or without NuShell.

### Rationale

1. **Self-Contained Bundle**
   - No hard dependency on NuShell
   - Works offline (no downloads required)
   - Fallback ensures functionality

2. **User Flexibility**
   - NuShell users get full features immediately
   - Non-NuShell users still get auto-config
   - User prompted to install NuShell (optional upgrade)

3. **Graceful Degradation**
   - With NuShell: Full three-layer architecture (best UX)
   - Without NuShell: Simple bash discovery (good UX)
   - Both modes provide auto-config injection

4. **Minimal Maintenance**
   - Only ~15 lines of bash fallback code
   - No library translation needed
   - NuShell libraries only used when available

5. **Daily UX Impact**
   - Users invoke 100s of times per day/week
   - Auto-config saves significant typing burden
   - Works regardless of NuShell availability

---

## Implementation Plan

### 1. Update `scripts/provisioning/install.sh`

**Key functions added**:

**a) Detect NuShell**:
```bash
check_nushell() {
    if command -v nu &> /dev/null; then
        NUSHELL_VERSION=$(nu --version 2>/dev/null | head -1)
        return 0
    else
        return 1
    fi
}
```

**b) Prompt user about NuShell**:
```bash
prompt_nushell() {
    # Shows installation guide if NuShell not found
    # Offers user choice: continue or install NuShell
    # Non-blocking (continues with fallback if needed)
}
```

**c) Create hybrid bash wrapper**:
```bash
create_bash_wrapper() {
    local dest="$1"
    local binary_name=$(basename "$dest")

    # Create wrapper that:
    # 1. Checks if NuShell is available
    # 2a. If YES: use full three-layer architecture
    # 2b. If NO: use bash-only config discovery
}
```

**d) Wrapper logic**:
```bash
#!/bin/bash
# Hybrid wrapper - tries NuShell first

if command -v nu &>/dev/null; then
    # Full mode: NuShell + libraries
    export NU_LIB_DIRS="$HOME/.config/syntaxis/scripts"
    exec nu "$HOME/.config/syntaxis/scripts/${BINARY_NAME}.nu" "$@"
fi

# Fallback: Bash-only config discovery
for cfg_path in \
    "$HOME/.config/syntaxis/${BINARY_NAME}.toml" \
    "$HOME/.config/syntaxis/config.toml" \
    ".syntaxis/${BINARY_NAME}.toml"; do

    if [[ -f "$cfg_path" ]]; then
        exec "$REAL_BINARY" --config "$cfg_path" "$@"
    fi
done

# No config found
exec "$REAL_BINARY" "$@"
```

### 2. Deploy NuShell Wrapper Scripts

**Add to `install.sh`**:
```bash
deploy_wrapper_scripts() {
    local scripts_dir="./scripts"
    local config_scripts_dir="$HOME/.config/syntaxis/scripts"

    mkdir -p "$config_scripts_dir"

    # Deploy shared library
    cp "$scripts_dir/syntaxis-lib.nu" "$config_scripts_dir/"

    # Deploy binary-specific wrappers
    for binary in syntaxis-cli syntaxis-tui syntaxis-api; do
        cp "$scripts_dir/${binary}.nu" "$config_scripts_dir/" 2>/dev/null || true
        cp "$scripts_dir/${binary}-lib.nu" "$config_scripts_dir/" 2>/dev/null || true
    done

    chmod +x "$config_scripts_dir"/*.nu
}
```

### 3. Update `provisioning.toml`

**Add wrapper scripts to artifacts**:
```toml
[artifacts]
# ... existing config ...

# Wrapper scripts for auto-config injection
wrapper_scripts = [
    "scripts/syntaxis-lib.nu",
    "scripts/syntaxis-cli.nu",
    "scripts/syntaxis-cli-lib.nu",
    "scripts/syntaxis-tui.nu",
    "scripts/syntaxis-tui-lib.nu",
    "scripts/syntaxis-api.nu",
    "scripts/syntaxis-api-lib.nu",
]
```

### 4. Update Bundle Structure

**Result after installation**:
```
User's system after bundle installation:
~/.cargo/bin/
├── syntaxis-cli          ← Bash wrapper
├── syntaxis-cli.real     ← Actual binary
├── syntaxis-tui          ← Bash wrapper
├── syntaxis-tui.real     ← Actual binary
└── syntaxis-api          ← Bash wrapper
└── syntaxis-api.real     ← Actual binary

~/.config/syntaxis/scripts/
├── syntaxis-lib.nu       ← Shared library
├── syntaxis-cli.nu       ← NuShell wrapper
├── syntaxis-cli-lib.nu   ← CLI utilities
├── syntaxis-tui.nu       ← NuShell wrapper
├── syntaxis-tui-lib.nu   ← TUI utilities
├── syntaxis-api.nu       ← NuShell wrapper
└── syntaxis-api-lib.nu   ← API utilities
```

---

## Technical Specifications

### Wrapper Scripts to Include

| Script | Size | Purpose |
|--------|------|---------|
| `syntaxis-lib.nu` | 1.1 KB | Shared library (config discovery) |
| `syntaxis-cli.nu` | 2.2 KB | CLI wrapper (auto-config injection) |
| `syntaxis-cli-lib.nu` | 1.5 KB | CLI utilities |
| `syntaxis-tui.nu` | 2.2 KB | TUI wrapper |
| `syntaxis-tui-lib.nu` | 743 B | TUI utilities |
| `syntaxis-api.nu` | 3.6 KB | API wrapper |
| `syntaxis-api-lib.nu` | 2.2 KB | API utilities |
| **Total** | ~13.5 KB | All wrapper infrastructure |

### Bundle Size Impact

- **Before**: Binaries + configs + docs = ~9.2 MB
- **After**: + wrapper scripts (~13.5 KB) = ~9.2 MB (negligible)

### Installation Steps

1. Extract bundle
2. Run `bash install.sh --interactive`
   - Installs binaries to `~/.local/bin/` (or custom prefix)
   - Deploys wrapper scripts to `~/.config/syntaxis/scripts/`
   - Renames binaries to `.real`
   - Creates bash wrappers at original locations
3. Run `bash setup-config.sh --interactive`
   - Creates configuration files

---

## Benefits

✅ **Users Don't Type `--config`**
- Every invocation automatically injects config path
- Saves millions of characters per year

✅ **Transparent**
- Users see no difference from direct binary
- Wrapper is invisible to end users

✅ **Flexible**
- Config files can be in multiple locations
- Wrapper discovers automatically

✅ **Consistent**
- Same experience as development installation
- Feature parity across installation methods

✅ **Maintainable**
- Clear separation: wrapper scripts vs binaries
- Easy to update wrappers without rebuilding binaries

---

## Trade-offs

### With NuShell (Full Mode)
**Pros**:
- ✅ Excellent user experience (no --config needed)
- ✅ Advanced config discovery (multiple paths, precedence)
- ✅ Full feature set available
- ✅ Consistent with development installation

**Cons**:
- ⚠️ Startup overhead (~50ms from NuShell)
- ⚠️ Requires NuShell to be installed
- ⚠️ Slightly more complex

### Without NuShell (Simplified Mode)
**Pros**:
- ✅ No external dependencies
- ✅ Works offline (self-contained)
- ✅ Still provides auto-config injection
- ✅ Simple bash-only fallback

**Cons**:
- ⚠️ Less advanced config discovery
- ⚠️ Simplified version of full features
- ⚠️ User prompted to install NuShell (optional)

### Overall Hybrid Approach
**Pros**:
- ✅ Self-contained bundle (no requirements)
- ✅ Works for all users (NuShell or not)
- ✅ Graceful degradation (best effort)
- ✅ Minimal maintenance (only ~15 lines bash fallback)
- ✅ User-aware (prompted to upgrade if desired)

**Cons**:
- ⚠️ Two code paths to test
- ⚠️ Slightly more complexity in wrapper
- ⚠️ NuShell libraries deployment (optional when not available)

---

## Risk Assessment

### Low Risk ✅
- Exact same code as development installation
- NuShell is already required for development
- Startup overhead is acceptable for CLI tools
- Can always use `.real` binaries if needed

---

## Implementation Checklist

- [ ] Modify `scripts/provisioning/install.sh` to create wrappers
- [ ] Add `deploy_wrapper_scripts()` function to install.sh
- [ ] Update `configs/provisioning.toml` to include wrapper scripts
- [ ] Update `scripts/provisioning/pack.nu` to package wrapper scripts
- [ ] Test bundle installation creates complete wrapper structure
- [ ] Update documentation (docs/installation.md, README.md)
- [ ] Rebuild bundle with wrapper support
- [ ] Verify wrapper functionality post-install

---

## Comparison: With vs Without Wrappers

### Without Wrappers (Current Bundle)
```bash
$ syntaxis-cli project list
# User must provide --config flag every time
$ syntaxis-cli --config ~/.config/syntaxis/syntaxis-cli.toml project list

# Burden: 50+ characters per invocation
# 100 invocations = 5,000+ characters of typing
```

### With Wrappers (Proposed)
```bash
$ syntaxis-cli project list
# Wrapper injects --config automatically
# Clean, simple, Unix-like experience

# Burden: 0 additional typing
# Users just type normal commands
```

---

## Related Documentation

- `docs/installation/WRAPPER_DESIGN.md` - Technical wrapper design
- `scripts/install-syntaxis.nu` - Development installation with wrappers
- `scripts/provisioning/install.sh` - Bundle installation (to be updated)

---

## Conclusion

**Decision**: Implement full wrapper deployment in bundle installations.

**Rationale**:
- High value (users don't type --config)
- Low complexity (existing code, ~14 KB)
- Better user experience
- Feature parity with development installation

This approach aligns with SYNTAXIS philosophy of providing excellent, transparent tooling for developers and teams.

---

**Status**: ACCEPTED - Ready for implementation

