Files
deusdata--codebase-memory-mcp/install.sh
T
wehub-resource-sync 41cb1c0170
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:28:05 +08:00

221 lines
6.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# install.sh — One-line installer for codebase-memory-mcp.
#
# Usage:
# curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
# curl -fsSL ... | bash -s -- --ui # Install the UI variant
# curl -fsSL ... | bash -s -- --dir /path # Custom install directory
#
# Environment:
# CBM_DOWNLOAD_URL Override base URL for downloads (for testing)
# Wrap in main() to prevent partial execution from piped downloads.
# If curl|bash is interrupted mid-transfer, bash would execute the partial
# script. With this wrapper, the function is defined but main() is never
# called because the final line hasn't arrived yet.
main() {
REPO="DeusData/codebase-memory-mcp"
INSTALL_DIR="$HOME/.local/bin"
VARIANT="standard"
SKIP_CONFIG=false
CBM_DOWNLOAD_URL="${CBM_DOWNLOAD_URL:-https://github.com/${REPO}/releases/latest/download}"
# Security: reject non-HTTPS download URLs (defense-in-depth)
case "$CBM_DOWNLOAD_URL" in
https://*|http://localhost*|http://127.0.0.1*) ;;
*) echo "error: refusing non-HTTPS download URL: $CBM_DOWNLOAD_URL" >&2; exit 1 ;;
esac
for arg in "$@"; do
case "$arg" in
--ui) VARIANT="ui" ;;
--standard) VARIANT="standard" ;;
--dir=*) INSTALL_DIR="${arg#--dir=}" ;;
--skip-config) SKIP_CONFIG=true ;;
--help|-h)
echo "Usage: install.sh [--ui] [--dir=<path>] [--skip-config]"
echo " --ui Install the UI variant (with graph visualization)"
echo " --standard Install the standard variant (default)"
echo " --dir PATH Install directory (default: ~/.local/bin)"
echo " --skip-config Skip automatic agent configuration"
exit 0
;;
esac
done
# Handle --dir <path> (space-separated)
prev=""
for arg in "$@"; do
if [ "$prev" = "--dir" ]; then
INSTALL_DIR="$arg"
fi
prev="$arg"
done
detect_os() {
case "$(uname -s)" in
Darwin) echo "darwin" ;;
Linux) echo "linux" ;;
MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
*) echo "error: unsupported OS: $(uname -s)" >&2; exit 1 ;;
esac
}
detect_arch() {
local arch
arch="$(uname -m)"
case "$arch" in
arm64|aarch64) echo "arm64" ;;
x86_64|amd64)
# Rosetta detection: shell reports x86_64 but hardware is Apple Silicon
if [ "$(uname -s)" = "Darwin" ] && sysctl -n machdep.cpu.brand_string 2>/dev/null | grep -qi apple; then
echo "arm64"
else
echo "amd64"
fi
;;
*) echo "error: unsupported architecture: $arch" >&2; exit 1 ;;
esac
}
OS=$(detect_os)
ARCH=$(detect_arch)
echo "codebase-memory-mcp installer"
echo " os: $OS"
echo " arch: $ARCH"
echo " variant: $VARIANT"
echo " target: $INSTALL_DIR/codebase-memory-mcp"
echo ""
# Build download URL
if [ "$OS" = "windows" ]; then
EXT="zip"
else
EXT="tar.gz"
fi
# Linux ships a fully-static "-portable" build; the standard linux binary
# dynamically links glibc 2.38+ and fails on older distros (Debian 11, RHEL 8,
# Ubuntu 20.04). macOS/Windows have no such variant.
PORTABLE=""
[ "$OS" = "linux" ] && PORTABLE="-portable"
if [ "$VARIANT" = "ui" ]; then
ARCHIVE="codebase-memory-mcp-ui-${OS}-${ARCH}${PORTABLE}.${EXT}"
else
ARCHIVE="codebase-memory-mcp-${OS}-${ARCH}${PORTABLE}.${EXT}"
fi
URL="${CBM_DOWNLOAD_URL}/${ARCHIVE}"
# Download
DLDIR=$(mktemp -d)
trap 'rm -rf "$DLDIR"' EXIT
echo "Downloading ${ARCHIVE}..."
if command -v curl &>/dev/null; then
curl -fSL --progress-bar -o "$DLDIR/$ARCHIVE" "$URL"
elif command -v wget &>/dev/null; then
wget -q --show-progress -O "$DLDIR/$ARCHIVE" "$URL"
else
echo "error: curl or wget required" >&2
exit 1
fi
# Checksum verification
CHECKSUM_URL="${CBM_DOWNLOAD_URL}/checksums.txt"
if curl -fsSL -o "$DLDIR/checksums.txt" "$CHECKSUM_URL" 2>/dev/null; then
EXPECTED=$(grep "$ARCHIVE" "$DLDIR/checksums.txt" | awk '{print $1}')
if [ -n "$EXPECTED" ]; then
if command -v sha256sum &>/dev/null; then
ACTUAL=$(sha256sum "$DLDIR/$ARCHIVE" | awk '{print $1}')
elif command -v shasum &>/dev/null; then
ACTUAL=$(shasum -a 256 "$DLDIR/$ARCHIVE" | awk '{print $1}')
else
ACTUAL=""
fi
if [ -n "$ACTUAL" ] && [ "$EXPECTED" != "$ACTUAL" ]; then
echo "error: CHECKSUM MISMATCH — download may be corrupted!" >&2
echo " expected: $EXPECTED" >&2
echo " actual: $ACTUAL" >&2
exit 1
elif [ -n "$ACTUAL" ]; then
echo "Checksum verified."
fi
fi
fi
# Extract
echo "Extracting..."
cd "$DLDIR"
if [ "$EXT" = "zip" ]; then
unzip -q "$ARCHIVE"
else
tar -xzf "$ARCHIVE"
fi
DLBIN="$DLDIR/codebase-memory-mcp"
if [ ! -f "$DLBIN" ]; then
echo "error: binary not found after extraction" >&2
exit 1
fi
# macOS: fix signing
if [ "$OS" = "darwin" ]; then
echo "Fixing macOS code signing..."
xattr -d com.apple.quarantine "$DLBIN" 2>/dev/null || true
codesign --sign - --force "$DLBIN" 2>/dev/null || true
fi
# Install
mkdir -p "$INSTALL_DIR"
DEST="$INSTALL_DIR/codebase-memory-mcp"
if [ -f "$DEST" ]; then
rm -f "$DEST"
fi
cp "$DLBIN" "$DEST"
chmod 755 "$DEST"
# Verify
VERSION=$("$DEST" --version 2>&1) || {
echo "error: installed binary failed to run" >&2
if [ "$OS" = "darwin" ]; then
echo " try: xattr -cr $DEST && codesign --force --sign - $DEST" >&2
fi
exit 1
}
echo "Installed: $VERSION"
# Configure agents
if [ "$SKIP_CONFIG" = true ]; then
echo ""
echo "Skipping agent configuration (--skip-config)"
else
echo ""
echo "Configuring coding agents..."
"$DEST" install -y 2>&1 || {
echo ""
echo "Agent configuration failed (non-fatal)."
echo "Run manually: codebase-memory-mcp install"
}
fi
# PATH check
if ! echo "$PATH" | tr ':' '\n' | grep -qx "$INSTALL_DIR"; then
echo ""
echo "NOTE: $INSTALL_DIR is not in your PATH."
echo "Add it to your shell config:"
echo ""
echo " echo 'export PATH=\"$INSTALL_DIR:\$PATH\"' >> ~/.zshrc"
fi
echo ""
echo "Done! Restart your coding agent to start using codebase-memory-mcp."
} # end main()
main "$@"