#!/usr/bin/env bash # openmemory installer: source checkout + shim. # # There are no published binaries or npm packages yet, and Bun is a hard # runtime requirement (@opentui/core loads its native terminal renderer via # bun:ffi; the adapters use bun:sqlite and Bun.spawn), so "install" means: # ensure Bun, clone this repo, bun install, and drop a launcher shim on PATH. # Re-running this script updates an existing install in place. # # Overrides (all exercised by cli/test/install-sh.test.ts): # OPENMEMORY_REPO clone URL (default: https://github.com/mem0ai/openmemory.git) # OPENMEMORY_INSTALL_DIR checkout (default: $XDG_DATA_HOME/openmemory/src) # OPENMEMORY_BIN_DIR shim dir (default: ~/.local/bin) set -euo pipefail REPO="${OPENMEMORY_REPO:-https://github.com/mem0ai/openmemory.git}" SRC="${OPENMEMORY_INSTALL_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/openmemory/src}" BIN_DIR="${OPENMEMORY_BIN_DIR:-$HOME/.local/bin}" info() { printf 'openmemory install: %s\n' "$*"; } fail() { printf 'openmemory install: error: %s\n' "$*" >&2; exit 1; } case "$(uname -s)" in Darwin | Linux) ;; *) fail "unsupported platform '$(uname -s)' — macOS and Linux only" ;; esac command -v git >/dev/null 2>&1 || fail "git is required (macOS: xcode-select --install; Debian/Ubuntu: apt install git)" resolve_bun() { if command -v bun >/dev/null 2>&1; then command -v bun return 0 fi local candidate="${BUN_INSTALL:-$HOME/.bun}/bin/bun" if [ -x "$candidate" ]; then printf '%s\n' "$candidate" return 0 fi return 1 } if ! BUN="$(resolve_bun)"; then command -v curl >/dev/null 2>&1 || fail "curl is required to install bun (https://bun.sh)" info "bun not found — installing from bun.sh" curl -fsSL https://bun.sh/install | bash >/dev/null || fail "bun installer failed — install it manually from https://bun.sh and re-run" BUN="$(resolve_bun)" || fail "bun install failed — install it manually from https://bun.sh and re-run" fi info "using bun at $BUN" mkdir -p "$BIN_DIR" SHIM="$BIN_DIR/openmemory" [ -d "$SHIM" ] && fail "$SHIM is a directory — remove it and re-run" if [ -e "$SRC" ]; then # .git is a dir in clones but a file in worktrees — -e covers both [ -e "$SRC/.git" ] || fail "$SRC exists but is not a git checkout — remove it and re-run" info "updating existing checkout at $SRC" git -C "$SRC" pull --ff-only --quiet else info "cloning $REPO into $SRC" mkdir -p "$(dirname "$SRC")" git clone --depth 1 --quiet "$REPO" "$SRC" fi info "installing runtime dependencies" (cd "$SRC/cli" && "$BUN" install --production) if [ -f "$SHIM" ] && ! grep -Fq "Managed by openmemory" "$SHIM"; then info "warning: replacing unrelated file at $SHIM" fi TMP="$(mktemp "$BIN_DIR/.openmemory.XXXXXX")" cat >"$TMP" <