#!/usr/bin/env sh # Gnodi AI Node installer. # # curl -fsSL https://get.gnodi-ai.com | sh # # Downloads the daemon, writes a config file, and installs a service. It never # overwrites an existing config — re-running upgrades the binary and leaves your # licence key and settings alone. set -eu REPO="${GNODI_REPO:-BlockReignTech/gnodi-ai-node}" VERSION="${GNODI_VERSION:-latest}" BIN_DIR="${GNODI_BIN_DIR:-/usr/local/bin}" BIN="$BIN_DIR/gnodi-ai-node" red() { printf '\033[31m%s\033[0m\n' "$*"; } bold() { printf '\033[1m%s\033[0m\n' "$*"; } info() { printf ' %s\n' "$*"; } die() { red "error: $*"; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "$1 is required but not installed"; } need curl need uname # --- platform ------------------------------------------------------------- os=$(uname -s | tr '[:upper:]' '[:lower:]') arch=$(uname -m) case "$arch" in x86_64|amd64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; *) die "unsupported architecture: $arch" ;; esac case "$os" in linux|darwin) ;; *) die "unsupported OS: $os (Windows: download the .exe from the releases page)" ;; esac if [ "$os" = "linux" ]; then CONF_DIR="${GNODI_CONF_DIR:-/etc/gnodi-ai-node}" else CONF_DIR="${GNODI_CONF_DIR:-/usr/local/etc/gnodi-ai-node}" fi CONF="$CONF_DIR/node.env" SUDO="" if [ "$(id -u)" -ne 0 ] && [ "${GNODI_NO_SUDO:-}" != "1" ]; then command -v sudo >/dev/null 2>&1 || die "run as root, or install sudo" SUDO="sudo" fi bold "Gnodi AI Node — installing for ${os}/${arch}" # --- download ------------------------------------------------------------- # GNODI_BASE_URL exists so this script can be exercised against a local # directory of artifacts instead of only against a live GitHub release. if [ -n "${GNODI_BASE_URL:-}" ]; then base="$GNODI_BASE_URL" elif [ "$VERSION" = "latest" ]; then base="https://github.com/$REPO/releases/latest/download" else base="https://github.com/$REPO/releases/download/$VERSION" fi asset="gnodi-ai-node_${os}_${arch}" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT INT TERM info "downloading $asset" curl -fsSL "$base/$asset" -o "$tmp/gnodi-ai-node" \ || die "download failed — check that $VERSION has a $os/$arch build" # Verify against the published checksums. A binary that will hold your licence # key and run unattended is worth one extra request. if curl -fsSL "$base/SHA256SUMS" -o "$tmp/SHA256SUMS" 2>/dev/null; then expected=$(grep " $asset\$" "$tmp/SHA256SUMS" | awk '{print $1}' || true) if [ -n "$expected" ]; then if command -v sha256sum >/dev/null 2>&1; then actual=$(sha256sum "$tmp/gnodi-ai-node" | awk '{print $1}') else actual=$(shasum -a 256 "$tmp/gnodi-ai-node" | awk '{print $1}') fi [ "$expected" = "$actual" ] || die "checksum mismatch — refusing to install" info "checksum verified" else red " warning: no checksum published for $asset" fi else red " warning: SHA256SUMS not available; skipping verification" fi chmod +x "$tmp/gnodi-ai-node" $SUDO mkdir -p "$BIN_DIR" $SUDO mv "$tmp/gnodi-ai-node" "$BIN" info "installed $BIN" # --- config --------------------------------------------------------------- $SUDO mkdir -p "$CONF_DIR" if [ -f "$CONF" ]; then info "keeping existing config at $CONF" else LICENSE_KEY="${LICENSE_KEY:-}" GATEWAY_URL="${GATEWAY_URL:-wss://gw.gnodi-ai.com/v1/agent}" NODESVC_URL="${NODESVC_URL:-https://nodes.gnodi-ai.com}" INFERENCE_URL="${INFERENCE_URL:-http://localhost:11434/v1}" if [ -z "$LICENSE_KEY" ]; then if [ -t 0 ]; then printf '\n Licence key (XXXX-XXXX-XXXX-XXXX): ' read -r LICENSE_KEY else # Piped from curl, so there is no terminal to prompt on. die "set LICENSE_KEY, e.g. curl -fsSL https://get.gnodi-ai.com | LICENSE_KEY=… sh" fi fi [ -n "$LICENSE_KEY" ] || die "a licence key is required" umask 077 $SUDO sh -c "cat > '$CONF'" </dev/null 2>&1; then $SUDO sh -c "cat > /etc/systemd/system/gnodi-ai-node.service" <%s%s\n' "$key" "$value" done) $SUDO sh -c "cat > '$PLIST'" < Labeltech.blockreign.gnodi-ai-node ProgramArguments$BIN EnvironmentVariables $env_xml STATE_DIR/usr/local/var/gnodi-ai-node RunAtLoad KeepAlive StandardOutPath/usr/local/var/log/gnodi-ai-node.log StandardErrorPath/usr/local/var/log/gnodi-ai-node.log EOF # The plist now carries the licence key, so lock it down like the config. $SUDO chmod 600 "$PLIST" $SUDO launchctl unload "$PLIST" 2>/dev/null || true $SUDO launchctl load -w "$PLIST" info "service started — tail -f /usr/local/var/log/gnodi-ai-node.log" info "after editing $CONF, re-run this installer to apply it" else info "no supported service manager found; run $BIN with the vars from $CONF" fi echo bold "Done." info "Dashboard: http://127.0.0.1:8080" info "Config: $CONF" info "Models are pulled automatically from the signed catalog on first start."