The GitHub account that hosted this repository is suspended, so the remote is dead and the vanity import github.com/ZacharyZhang-NY/ely-eye/... no longer resolves. The Go module path is that import, so it moves with the host: git.zacharyzhang.com serves a go-import meta tag for the nested ely-eye-mcp submodule, which go build and go get both need. The installers read release assets from the host too, so their API and download URLs move with it. The release workflow's -ldflags symbol path is the module path, so it moves as well; a build stamped with the new path prints the stamped version.
144 lines
4.5 KiB
Bash
144 lines
4.5 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Ely-Eye MCP installer for Linux and macOS.
|
|
#
|
|
# curl -fsSL https://git.zacharyzhang.com/ZacharyZhang-NY/ely-eye/raw/branch/main/ely-eye-mcp/install.sh | bash
|
|
#
|
|
# By default it downloads a prebuilt, checksum-verified binary for this platform
|
|
# and needs no toolchain. Run with --method source from a repository checkout to
|
|
# build with Go instead. The binary is installed into <ely-eye-home>/bin and
|
|
# registered with Codex and Claude Code.
|
|
|
|
REPO="ZacharyZhang-NY/ely-eye"
|
|
CLIENT="both"
|
|
SCOPE="project"
|
|
SERVER_NAME="ely-eye"
|
|
METHOD="auto"
|
|
VERSION=""
|
|
PROJECT_ROOT=""
|
|
ELY_EYE_HOME=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--client) CLIENT="$2"; shift 2 ;;
|
|
--scope) SCOPE="$2"; shift 2 ;;
|
|
--server-name) SERVER_NAME="$2"; shift 2 ;;
|
|
--method) METHOD="$2"; shift 2 ;;
|
|
--version) VERSION="$2"; shift 2 ;;
|
|
--project-root) PROJECT_ROOT="$2"; shift 2 ;;
|
|
--ely-eye-home) ELY_EYE_HOME="$2"; shift 2 ;;
|
|
--repo) REPO="$2"; shift 2 ;;
|
|
*) echo "unknown argument: $1" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
case "$METHOD" in auto | download | source) ;; *) echo "method must be auto, download, or source" >&2; exit 1 ;; esac
|
|
|
|
SOURCE="${BASH_SOURCE[0]:-}"
|
|
SCRIPT_DIR=""
|
|
if [[ -n "$SOURCE" && -f "$SOURCE" ]]; then
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "$SOURCE")" && pwd)"
|
|
fi
|
|
|
|
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/go.mod" ]]; then
|
|
PROJECT_ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
|
else
|
|
PROJECT_ROOT="$PWD"
|
|
fi
|
|
fi
|
|
PROJECT_ROOT="$(cd -- "$PROJECT_ROOT" && pwd)"
|
|
[[ -z "$ELY_EYE_HOME" ]] && ELY_EYE_HOME="$PROJECT_ROOT/.ely_eye"
|
|
mkdir -p "$ELY_EYE_HOME/bin"
|
|
BINARY="$ELY_EYE_HOME/bin/ely-eye-mcp"
|
|
|
|
detect_platform() {
|
|
local os arch
|
|
case "$(uname -s)" in
|
|
Linux) os="linux" ;;
|
|
Darwin) os="darwin" ;;
|
|
*) echo "unsupported operating system: $(uname -s)" >&2; exit 1 ;;
|
|
esac
|
|
case "$(uname -m)" in
|
|
x86_64 | amd64) arch="amd64" ;;
|
|
arm64 | aarch64) arch="arm64" ;;
|
|
*) echo "unsupported architecture: $(uname -m)" >&2; exit 1 ;;
|
|
esac
|
|
echo "${os}_${arch}"
|
|
}
|
|
|
|
sha256() {
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
sha256sum "$1" | awk '{print $1}'
|
|
else
|
|
shasum -a 256 "$1" | awk '{print $1}'
|
|
fi
|
|
}
|
|
|
|
resolve_version() {
|
|
if [[ -n "$VERSION" ]]; then echo "$VERSION"; return 0; fi
|
|
local body
|
|
body="$(curl -fsSL "https://git.zacharyzhang.com/api/v1/repos/${REPO}/releases" 2>/dev/null)" || return 0
|
|
printf '%s\n' "$body" \
|
|
| grep -oE '"tag_name": *"mcp-[^"]*"' \
|
|
| head -n 1 \
|
|
| sed -E 's/.*"(mcp-[^"]*)".*/\1/' || true
|
|
}
|
|
|
|
build_from_source() {
|
|
command -v go >/dev/null 2>&1 || { echo "Go 1.25 or newer is required to build from source." >&2; exit 1; }
|
|
[[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/go.mod" ]] || { echo "source builds must run from a repository checkout." >&2; exit 1; }
|
|
echo "Building ely-eye-mcp from source with Go."
|
|
( cd "$SCRIPT_DIR" && CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o "$BINARY" ./cmd/ely-eye-mcp )
|
|
}
|
|
|
|
download_binary() {
|
|
local tag="$1" platform asset url sums tmp
|
|
platform="$(detect_platform)"
|
|
asset="ely-eye-mcp_${platform}.tar.gz"
|
|
url="https://git.zacharyzhang.com/${REPO}/releases/download/${tag}/${asset}"
|
|
sums="https://git.zacharyzhang.com/${REPO}/releases/download/${tag}/ely-eye-mcp_SHA256SUMS.txt"
|
|
tmp="$(mktemp -d)"
|
|
trap 'rm -rf "$tmp"' RETURN
|
|
echo "Downloading $asset from release $tag."
|
|
curl -fsSL "$url" -o "$tmp/$asset"
|
|
curl -fsSL "$sums" -o "$tmp/SHA256SUMS"
|
|
local expected actual
|
|
expected="$(grep -E " \*?${asset}\$" "$tmp/SHA256SUMS" | awk '{print $1}' || true)"
|
|
[[ -n "$expected" ]] || { echo "checksum for $asset not found in release." >&2; exit 1; }
|
|
actual="$(sha256 "$tmp/$asset")"
|
|
[[ "$expected" == "$actual" ]] || { echo "checksum mismatch for $asset." >&2; exit 1; }
|
|
tar -xzf "$tmp/$asset" -C "$tmp"
|
|
mv "$tmp/ely-eye-mcp" "$BINARY"
|
|
chmod +x "$BINARY"
|
|
}
|
|
|
|
acquire() {
|
|
case "$METHOD" in
|
|
source) build_from_source; return ;;
|
|
download)
|
|
local tag; tag="$(resolve_version)"
|
|
[[ -n "$tag" ]] || { echo "no prebuilt release found for ${REPO}." >&2; exit 1; }
|
|
download_binary "$tag"; return ;;
|
|
auto)
|
|
local tag; tag="$(resolve_version)"
|
|
if [[ -n "$tag" ]]; then
|
|
download_binary "$tag"
|
|
else
|
|
echo "No prebuilt release available; building from source."
|
|
build_from_source
|
|
fi ;;
|
|
esac
|
|
}
|
|
|
|
acquire
|
|
|
|
"$BINARY" setup \
|
|
--client "$CLIENT" \
|
|
--scope "$SCOPE" \
|
|
--server-name "$SERVER_NAME" \
|
|
--project-root "$PROJECT_ROOT" \
|
|
--ely-eye-home "$ELY_EYE_HOME" \
|
|
--binary "$BINARY"
|