|
1 | 1 | #!/bin/sh |
2 | 2 | set -e |
3 | 3 |
|
| 4 | +# Usage: install.sh [stable|latest|VERSION] |
| 5 | +CHANNEL="${1:-stable}" |
| 6 | + |
| 7 | +case "$CHANNEL" in |
| 8 | + stable|latest) ;; |
| 9 | + v*|[0-9]*) ;; |
| 10 | + *) |
| 11 | + echo "Usage: $0 [stable|latest|VERSION]" >&2 |
| 12 | + exit 1 |
| 13 | + ;; |
| 14 | +esac |
| 15 | + |
4 | 16 | REPO="MiniMax-AI-Dev/minimax-cli" |
5 | | -INSTALL_DIR="${MINIMAX_INSTALL_DIR:-/usr/local/bin}" |
6 | | - |
7 | | -OS=$(uname -s | tr '[:upper:]' '[:lower:]') |
8 | | -ARCH=$(uname -m) |
9 | | -case "$ARCH" in |
10 | | - x86_64) ARCH="x64" ;; |
11 | | - aarch64|arm64) ARCH="arm64" ;; |
12 | | - *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; |
| 17 | +INSTALL_DIR="${MINIMAX_INSTALL_DIR:-$HOME/.local/bin}" |
| 18 | + |
| 19 | +# Dependency check: curl or wget |
| 20 | +if command -v curl >/dev/null 2>&1; then |
| 21 | + download() { curl -fsSL "$1"; } |
| 22 | + download_to() { curl -fsSL -o "$2" "$1"; } |
| 23 | +elif command -v wget >/dev/null 2>&1; then |
| 24 | + download() { wget -qO- "$1"; } |
| 25 | + download_to() { wget -qO "$2" "$1"; } |
| 26 | +else |
| 27 | + echo "curl or wget is required." >&2; exit 1 |
| 28 | +fi |
| 29 | + |
| 30 | +# Detect OS |
| 31 | +case "$(uname -s)" in |
| 32 | + Darwin) OS="darwin" ;; |
| 33 | + Linux) OS="linux" ;; |
| 34 | + *) echo "Unsupported OS: $(uname -s)" >&2; exit 1 ;; |
| 35 | +esac |
| 36 | + |
| 37 | +# Detect architecture |
| 38 | +case "$(uname -m)" in |
| 39 | + x86_64|amd64) ARCH="x64" ;; |
| 40 | + arm64|aarch64) ARCH="arm64" ;; |
| 41 | + *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; |
| 42 | +esac |
| 43 | + |
| 44 | +# Rosetta 2: x64 shell on ARM Mac → use native arm64 binary |
| 45 | +if [ "$OS" = "darwin" ] && [ "$ARCH" = "x64" ]; then |
| 46 | + if [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = "1" ]; then |
| 47 | + ARCH="arm64" |
| 48 | + fi |
| 49 | +fi |
| 50 | + |
| 51 | +# musl detection on Linux |
| 52 | +PLATFORM="${OS}-${ARCH}" |
| 53 | +if [ "$OS" = "linux" ]; then |
| 54 | + if [ -f /lib/libc.musl-x86_64.so.1 ] || \ |
| 55 | + [ -f /lib/libc.musl-aarch64.so.1 ] || \ |
| 56 | + ldd /bin/ls 2>&1 | grep -q musl; then |
| 57 | + PLATFORM="${OS}-${ARCH}-musl" |
| 58 | + fi |
| 59 | +fi |
| 60 | + |
| 61 | +# Resolve version from channel |
| 62 | +GH_API="https://api.github.com/repos/${REPO}" |
| 63 | +case "$CHANNEL" in |
| 64 | + stable) |
| 65 | + VERSION=$(download "${GH_API}/releases/latest" \ |
| 66 | + | grep '"tag_name"' | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/') |
| 67 | + ;; |
| 68 | + latest) |
| 69 | + VERSION=$(download "${GH_API}/releases?per_page=1" \ |
| 70 | + | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/') |
| 71 | + ;; |
| 72 | + *) |
| 73 | + case "$CHANNEL" in v*) VERSION="$CHANNEL" ;; *) VERSION="v${CHANNEL}" ;; esac |
| 74 | + ;; |
13 | 75 | esac |
14 | 76 |
|
15 | | -BINARY="minimax-${OS}-${ARCH}" |
16 | | -URL="https://github.com/${REPO}/releases/latest/download/${BINARY}" |
| 77 | +if [ -z "$VERSION" ]; then |
| 78 | + echo "Failed to resolve version." >&2; exit 1 |
| 79 | +fi |
17 | 80 |
|
18 | | -echo "Downloading ${BINARY}..." |
19 | | -curl -fsSL "$URL" -o "${INSTALL_DIR}/minimax" |
20 | | -chmod +x "${INSTALL_DIR}/minimax" |
21 | | -echo "Installed minimax to ${INSTALL_DIR}/minimax" |
22 | | -"${INSTALL_DIR}/minimax" --version |
| 81 | +echo "Installing minimax ${VERSION} for ${PLATFORM}..." |
| 82 | + |
| 83 | +# Fetch manifest and extract SHA256 (pure sh, no jq required) |
| 84 | +BASE_URL="https://github.com/${REPO}/releases/download/${VERSION}" |
| 85 | +MANIFEST=$(download "${BASE_URL}/manifest.json") || { |
| 86 | + echo "Failed to fetch manifest.json" >&2; exit 1 |
| 87 | +} |
| 88 | +CHECKSUM=$(printf '%s' "$MANIFEST" | tr -d '\n' | \ |
| 89 | + sed "s/.*\"${PLATFORM}\"[^}]*\"checksum\" *: *\"\([a-f0-9]*\)\".*/\1/") |
| 90 | + |
| 91 | +if [ -z "$CHECKSUM" ] || [ "${#CHECKSUM}" -ne 64 ]; then |
| 92 | + echo "Platform '${PLATFORM}' not found in manifest." >&2; exit 1 |
| 93 | +fi |
| 94 | + |
| 95 | +# Download binary to temp file |
| 96 | +TMP=$(mktemp) |
| 97 | +trap 'rm -f "$TMP"' EXIT |
| 98 | + |
| 99 | +download_to "${BASE_URL}/minimax-${PLATFORM}" "$TMP" || { |
| 100 | + echo "Download failed." >&2; exit 1 |
| 101 | +} |
| 102 | + |
| 103 | +# Verify SHA256 |
| 104 | +if command -v shasum >/dev/null 2>&1; then |
| 105 | + ACTUAL=$(shasum -a 256 "$TMP" | cut -d' ' -f1) |
| 106 | +elif command -v sha256sum >/dev/null 2>&1; then |
| 107 | + ACTUAL=$(sha256sum "$TMP" | cut -d' ' -f1) |
| 108 | +else |
| 109 | + echo "shasum or sha256sum is required." >&2; exit 1 |
| 110 | +fi |
| 111 | + |
| 112 | +if [ "$ACTUAL" != "$CHECKSUM" ]; then |
| 113 | + echo "Checksum verification failed." >&2; exit 1 |
| 114 | +fi |
| 115 | + |
| 116 | +chmod +x "$TMP" |
| 117 | +mkdir -p "$INSTALL_DIR" |
| 118 | +mv "$TMP" "${INSTALL_DIR}/minimax" |
| 119 | + |
| 120 | +echo "Installed minimax ${VERSION} to ${INSTALL_DIR}/minimax" |
| 121 | + |
| 122 | +# Warn if install dir is not in PATH |
| 123 | +case ":${PATH}:" in |
| 124 | + *":${INSTALL_DIR}:"*) ;; |
| 125 | + *) |
| 126 | + printf '\nNote: %s is not in PATH. Add to your shell profile:\n' "$INSTALL_DIR" |
| 127 | + printf ' export PATH="%s:$PATH"\n\n' "$INSTALL_DIR" |
| 128 | + ;; |
| 129 | +esac |
0 commit comments