#!/usr/bin/env nu # install-with-presets.nu - Local syntaxis installer with preset reference # # This script handles LOCAL installation and setup only. # For remote/distributed deployments, use project-provisioning: # https://github.com/Akasha/project-provisioning # # This script: # - Installs syntaxis binaries locally # - Configures local services (optional) # - Shows preset templates (reference only) # # Architecture: # syntaxis: Binary distribution + LOCAL installation # project-provisioning: Remote infrastructure + multi-host orchestration # # USAGE: # nu scripts/provisioning/install-with-presets.nu --preset local # nu scripts/provisioning/install-with-presets.nu --list-presets # nu scripts/provisioning/install-with-presets.nu help def main [ --preset: string = "local" --verbose: bool = false --list-presets: bool = false ...args ] { # Handle help and list commands let first_arg = ($args | first) if ($first_arg == "help") or ($first_arg == "--help") or ($first_arg == "-h") { print_help return } if $list_presets or ($first_arg == "list-presets") { list_available_presets return } print_header # Only allow LOCAL presets that make sense for this machine let allowed_local_presets = ["minimal", "local", "dev"] if not ($preset in $allowed_local_presets) { print "❌ Error: preset '$preset' is not supported for local installation" print "" print "For remote deployments (staging, production, kubernetes)," print "use project-provisioning:" print " https://github.com/Akasha/project-provisioning" print "" print "Allowed LOCAL presets:" $allowed_local_presets | each { |p| print $" • ($p)" } return } print_divider print $"Selected preset: (ansi cyan)($preset)(ansi reset)" # Load preset configuration (for reference) let install_config = load_preset_reference $preset if ($install_config == null) { print $"❌ Unknown preset: ($preset)" return } # Show preset information print_preset_info $preset $install_config # Pre-flight checks (minimal) print_divider print "✓ Running pre-flight checks..." let checks_passed = (run_preflight_checks_local $preset) if not $checks_passed { print "⚠️ Some checks failed - proceed anyway? (y/n)" # For automation, continue anyway } # Check provctl availability print_divider print "🔍 Checking environment..." let provctl_info = (detect_provctl_availability) let provctl_available = ($provctl_info.available) if $verbose { print $" provctl available: ($provctl_available)" if $provctl_available { print $" provctl path: ($provctl_info.path)" print $" provctl version: ($provctl_info.version)" } } # Determine provctl usage let use_provctl = match $provctl { "required" => { if not $provctl_available { print "❌ provctl is required but not available" print "Install from: https://github.com/Akasha/provctl" return } true } "disabled" => false "auto" => { if $provctl_available and ($preset_config.provctl_recommended? ?? false) { true } else { false } } _ => false } if $use_provctl { print "✓ provctl will be used for service management" } else { print "ℹ️ Service management: manual setup (generate scripts)" } # Installation phase print_divider print "📦 Installing syntaxis binaries..." # Determine which binaries to install based on preset let binaries_to_install = (get_binaries_for_preset $effective_preset $preset_config) if ($binaries_to_install | length) == 0 { print "ℹ️ No binaries to install for this preset" } else { # Call the original installer print $"Installing ($binaries_to_install | length) binary(ies)..." try { # Run original installer for binaries nu scripts/install-syntaxis.nu all 2>/dev/null print "✓ Binaries installed" } catch { |err| print $"⚠️ Binary installation had issues: ($err)" } } # Service setup phase let services_config = ($preset_config.services?) if ($services_config != null) { print_divider print "🚀 Setting up services..." setup_services $effective_preset $services_config $use_provctl $provctl_info } # Database configuration print_divider print "🗄️ Configuring database..." let db_backend = ($preset_config.database_backend? ?? "sqlite") setup_database $db_backend $effective_preset # Create manifest print_divider print "📋 Creating installation manifest..." create_installation_manifest $effective_preset $preset_config $use_provctl # Summary and next steps print_divider print_installation_summary $effective_preset $preset_config } # Load configuration from file def load_config_from_file [config_path: string] { if not ($config_path | path exists) { print $"⚠️ Configuration not found: ($config_path)" return null } try { open $config_path } catch { |err| print $"❌ Failed to load configuration: ($err)" return null } } # Generate installation config output def generate_installation_config [preset: string, config: record]: nothing -> string { let output = $"# Generated installation configuration for preset: ($preset) [installation] preset = \"($preset)\" interactive = false [database] backend = \"($config.database_backend?)\" [services] " # Add services let services_str = ( if ($config.services? != null) { ($config.services | to toml) } else { "" } ) $output + $services_str } # Detect provctl availability def detect_provctl_availability []: nothing -> record { try { nu scripts/provisioning/detect-provctl.nu } catch { { available: false, path: null, version: null, commands: [], backends: [] } } } # Select preset interactively def select_preset_interactive [config: record]: nothing -> string { let available_presets = ($config | get preset | keys) if ($available_presets | length) == 0 { return "local" } print "" print "Available installation presets:" print "" for (idx, preset) in ($available_presets | enumerate) { let preset_info = ($config.preset | get $preset) let name = ($preset_info.name? ?? $preset) let desc = ($preset_info.description? ?? "") print $" ($idx + 1)) ($name)" if ($desc != "") { print $" ($desc)" } print "" } # Get user input let choice = (input "Select preset (1-$(($available_presets | length)): ") let choice_num = (try { $choice | into int } catch { 1 }) if ($choice_num > 0) and ($choice_num <= ($available_presets | length)) { $available_presets | get ($choice_num - 1) } else { "local" } } # Get binaries for preset def get_binaries_for_preset [preset: string, config: record]: nothing -> list { ["syntaxis-cli", "syntaxis-tui"] # Core binaries always installed # API and others conditional on preset } # Setup database def setup_database [backend: string, preset: string] { print $"Database backend: (ansi cyan)($backend)(ansi reset)" match $backend { "sqlite" => { let db_path = "~/.local/share/core/workspace.db" print $" Location: ($db_path)" print $" Status: File-based (automatic)" } "surrealdb" => { print $" Mode: Check configs/database-surrealdb.toml" print $" Status: Requires configuration" } _ => { print $" Unknown backend: ($backend)" } } } # Setup services def setup_services [preset: string, services: record, use_provctl: bool, provctl_info: record] { print $"Services for preset: (ansi cyan)($preset)(ansi reset)" let service_list = [] # Iterate through services try { $services | transpose | each { |item| let service_name = $item.key let service_config = $item.value if ($service_config.enabled? ?? false) { print $" ✓ ($service_name)" if ($service_config.auto_start? ?? false) { print $" └─ auto-start: enabled" } } } } catch { print " (no services configured)" } if $use_provctl { print "" print "📌 Service deployment with provctl:" print " Run: nu scripts/provisioning/provctl-services.nu deploy $preset" } } # Create installation manifest def create_installation_manifest [preset: string, config: record, used_provctl: bool] { let manifest_path = ".syntaxis/manifest-installation.toml" let timestamp = (date now | format date "%Y-%m-%d %H:%M:%S") let manifest = $"# Installation Manifest [installation] preset = \"($preset)\" timestamp = \"($timestamp)\" provctl_used = ($used_provctl) config_location = \"configs/installation.toml\" [preset_info] name = \"($config.name?)\" description = \"($config.description?)\" [database] backend = \"($config.database_backend?)\" [notes] # To view services: nu scripts/provisioning/provctl-services.nu list $preset # To manage services: nu scripts/provisioning/provctl-services.nu deploy $preset " try { ^mkdir -p .syntaxis echo $manifest | save $manifest_path print $"✓ Manifest saved: ($manifest_path)" } catch { |err| print $"⚠️ Failed to create manifest: ($err)" } } # Print header def print_header [] { print "" print "┌────────────────────────────────────────────────┐" print "│ syntaxis Enhanced Installer with provctl │" print "│ Smart presets + Service Management │" print "└────────────────────────────────────────────────┘" print "" } # Print divider def print_divider [] { print "─────────────────────────────────────────────────" } # Print preset info def print_preset_info [name: string, config: record] { print $"Preset: (ansi cyan)($name)(ansi reset)" print $" Name: ($config.name?)" print $" Description: ($config.description?)" print $" Database: ($config.database_backend?)" } # Print installation summary def print_installation_summary [preset: string, config: record] { print "Installation complete!" print "" print "Next steps:" match $preset { "local" => { print " 1. Try the CLI: syntaxis-cli init my-project" print " 2. Use TUI: syntaxis-tui" print "" print "To upgrade later: nu scripts/provisioning/install-with-presets.nu --preset dev" } "dev" => { print " 1. Start services: provctl start surrealdb && provctl start nats" print " 2. Or use: docker-compose up" print " 3. Open dashboard: http://localhost:3000" print " 4. Use API: curl http://localhost:3000/health" } "staging" => { print " 1. Start Docker services: docker-compose -f docker/docker-compose.yml up" print " 2. Verify health: curl http://localhost:3000/health" print " 3. Open dashboard: http://localhost:3000" print " 4. Monitor: http://localhost:9090" } "production" => { print " 1. Review Kubernetes manifests: ls kubernetes/" print " 2. Create namespace: kubectl create namespace syntaxis" print " 3. Deploy: kubectl apply -f kubernetes/" print " 4. Monitor: kubectl logs -n syntaxis deployment/syntaxis-api" } _ => { print " Installation complete. Run 'syntaxis-cli --help' for usage." } } print "" print "Documentation: docs/INSTALLATION_CONTEXTS.md" print "" } # Print help message def print_help [] { print "" print "syntaxis Enhanced Installer with Presets and provctl Integration" print "" print "USAGE:" print " nu scripts/provisioning/install-with-presets.nu [OPTIONS]" print "" print "OPTIONS:" print " --preset Installation preset (local, minimal, dev, staging, production, custom)" print " --interactive Interactive mode - ask questions" print " --config Load configuration from file" print " --generate-config Generate config file and exit" print " --provctl provctl mode: auto (default), required, disabled" print " --verbose Verbose output" print " --list-presets List all available presets" print " -h, --help Show this help message" print "" print "EXAMPLES:" print " # Simple local installation" print " nu scripts/provisioning/install-with-presets.nu" print "" print " # Development with services" print " nu scripts/provisioning/install-with-presets.nu --preset dev" print "" print " # Interactive setup" print " nu scripts/provisioning/install-with-presets.nu --interactive" print "" print " # Generate configuration" print " nu scripts/provisioning/install-with-presets.nu --preset staging --generate-config" print "" print " # Install from configuration file" print " nu scripts/provisioning/install-with-presets.nu --config my-install.toml" print "" print "DOCUMENTATION:" print " docs/INSTALLATION_CONTEXTS.md - Detailed guide for each preset" print " CLAUDE.md - Installation commands reference" print "" } # List all available presets def list_available_presets [] { let config = ( try { open "configs/installation.toml" } catch { return } ) let presets = ($config | get preset | keys | sort) print "" print "Available Installation Presets:" print "" for preset in $presets { let preset_config = ($config.preset | get $preset) let name = ($preset_config.name? ?? $preset) let desc = ($preset_config.description? ?? "No description") let db = ($preset_config.database_backend? ?? "unknown") print $" (ansi cyan)→(ansi reset) ($preset)" print $" Name: ($name)" print $" Description: ($desc)" print $" Database: ($db)" print "" } } # Run pre-flight checks def run_preflight_checks [preset: string]: nothing -> bool { mut all_passed = true # Check if Rust is installed if (try { which cargo } catch { null }) == null { print " ⚠️ Rust/Cargo not found (required for building)" $all_passed = false } else { print " ✓ Rust/Cargo detected" } # Check if NuShell is available if (try { which nu } catch { null }) == null { print " ❌ NuShell required but not found" return false } else { print " ✓ NuShell detected" } # Check if configs exist if not ("configs/installation.toml" | path exists) { print " ❌ configs/installation.toml not found" return false } else { print " ✓ Installation config found" } # Preset-specific checks match $preset { "dev" | "staging" => { if (try { which surreal } catch { null }) == null { print " ⚠️ SurrealDB CLI not found (can install with: cargo install surrealdb-cli)" # Not fatal, warn but continue } else { print " ✓ SurrealDB detected" } } "staging" | "production" => { if (try { which docker } catch { null }) == null { print " ⚠️ Docker not found (required for this preset)" $all_passed = false } else { print " ✓ Docker detected" } } _ => {} } $all_passed }