Last active
June 20, 2026 23:53
-
-
Save patrickjholloway/fee78be2b6f25ef8a901ff41ababd940 to your computer and use it in GitHub Desktop.
Levi Installation Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Levi Installation Script | |
| # Usage: curl -fsSL https://gist.github.com/patrickjholloway/fee78be2b6f25ef8a901ff41ababd940 | sh | |
| # | |
| # Detects Node.js, then launches the interactive TUI installer. | |
| # For the legacy sequential installer: bash install-legacy.sh | |
| set -euo pipefail | |
| # ── Colors ──────────────────────────────────────────────────────────────────── | |
| if [[ -t 1 ]]; then | |
| BOLD='\033[1m' DIM='\033[2m' RED='\033[0;31m' GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' | |
| else | |
| BOLD='' DIM='' RED='' GREEN='' YELLOW='' BLUE='' NC='' | |
| fi | |
| # ── Detect system ───────────────────────────────────────────────────────────── | |
| OS=$(uname -s | tr '[:upper:]' '[:lower:]') | |
| ARCH=$(uname -m) | |
| case "$ARCH" in | |
| x86_64) ARCH="x64" ;; | |
| aarch64|arm64) ARCH="arm64" ;; | |
| *) | |
| echo -e "${RED}Unsupported architecture: $ARCH${NC}" | |
| echo " Levi supports x86_64 and arm64." | |
| exit 1 | |
| ;; | |
| esac | |
| case "$OS" in | |
| linux|darwin) ;; | |
| *) | |
| echo -e "${RED}Unsupported OS: $OS${NC}" | |
| echo " Levi supports Linux and macOS." | |
| exit 1 | |
| ;; | |
| esac | |
| # ── Ensure Node 18+ ────────────────────────────────────────────────────────── | |
| MIN_NODE=18 | |
| HAS_NODE=false | |
| if command -v node &>/dev/null; then | |
| NODE_VER=$(node -e 'console.log(process.versions.node.split(".")[0])') | |
| if (( NODE_VER >= MIN_NODE )); then | |
| HAS_NODE=true | |
| fi | |
| fi | |
| if [[ "$HAS_NODE" != "true" ]]; then | |
| echo "" | |
| echo -e " ${BOLD}Levi requires Node.js ${MIN_NODE} or later.${NC}" | |
| echo "" | |
| if [[ "$OS" == "linux" ]]; then | |
| echo " Install Node.js:" | |
| echo -e " ${DIM}curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -${NC}" | |
| echo -e " ${DIM}sudo apt-get install -y nodejs${NC}" | |
| else | |
| echo " Install Node.js:" | |
| echo -e " ${DIM}brew install node${NC}" | |
| fi | |
| echo "" | |
| echo " Then re-run:" | |
| echo -e " ${BLUE}curl -fsSL https://get.levi.sh | sh${NC}" | |
| exit 1 | |
| fi | |
| # ── npm registry ────────────────────────────────────────────────────────────── | |
| REGISTRY_ARGS="" | |
| if [[ -n "${LEVI_NPM_REGISTRY:-}" ]]; then | |
| REGISTRY_ARGS="--registry ${LEVI_NPM_REGISTRY}" | |
| fi | |
| # ── Parse installer args for fail-fast checks ──────────────────────────────── | |
| PROFILE="" | |
| YES_MODE=false | |
| for arg in "$@"; do | |
| case "$arg" in | |
| --yes|-y) YES_MODE=true ;; | |
| --profile=*) PROFILE="${arg#*=}" ;; | |
| --help|-h) | |
| echo "Levi installer bootstrap" | |
| echo "" | |
| echo "Usage:" | |
| echo " curl -fsSL https://get.levi.sh | sh" | |
| echo " curl -fsSL https://get.levi.sh | sh -s -- --profile local --yes" | |
| echo "" | |
| echo "Options forwarded to @marsman-io/levi-installer:" | |
| echo " --profile <cloud|local> Select install profile" | |
| echo " --yes, -y Non-interactive mode (skip prompts)" | |
| echo "" | |
| echo "Environment:" | |
| echo " LEVI_NPM_REGISTRY=<url> Custom npm registry" | |
| exit 0 | |
| ;; | |
| esac | |
| done | |
| for ((i=1; i<=$#; i++)); do | |
| if [[ "${!i}" == "--profile" ]]; then | |
| next_index=$((i + 1)) | |
| if (( next_index <= $# )); then | |
| PROFILE="${!next_index}" | |
| fi | |
| fi | |
| done | |
| if [[ -n "$PROFILE" && "$PROFILE" != "cloud" && "$PROFILE" != "local" ]]; then | |
| echo -e "${RED}Invalid --profile: ${PROFILE}${NC}" | |
| echo " Expected one of: cloud, local" | |
| echo " See install docs: https://github.com/marsman-io/levi/blob/main/docs/bootstrap/INSTALL.md" | |
| exit 1 | |
| fi | |
| if [[ "$YES_MODE" == "true" && "$PROFILE" == "local" ]]; then | |
| if ! sudo -n true 2>/dev/null; then | |
| echo -e "${YELLOW}Non-interactive local install needs sudo access up front.${NC}" | |
| echo " Re-run without --yes for interactive prompts, or enable sudo for this session." | |
| echo " See troubleshooting: https://github.com/marsman-io/levi/blob/main/docs/bootstrap/INSTALL.md#troubleshooting" | |
| exit 1 | |
| fi | |
| fi | |
| # ── Launch installer TUI ───────────────────────────────────────────────────── | |
| echo "" | |
| echo -e " ${BLUE}${BOLD}Levi${NC} — Agent Control Plane" | |
| echo -e " ${DIM}Launching installer...${NC}" | |
| echo "" | |
| exec npx --yes @marsman-io/levi-installer ${REGISTRY_ARGS} "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment