Skip to content

Instantly share code, notes, and snippets.

@patrickjholloway
Last active June 20, 2026 23:53
Show Gist options
  • Select an option

  • Save patrickjholloway/fee78be2b6f25ef8a901ff41ababd940 to your computer and use it in GitHub Desktop.

Select an option

Save patrickjholloway/fee78be2b6f25ef8a901ff41ababd940 to your computer and use it in GitHub Desktop.
Levi Installation Script
#!/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