#!/bin/sh # Download and verify a versioned aid release before installing without root. # Dependencies: curl, tar, mktemp, and sha256sum or shasum (cargo on unsupported targets). set -eu repo=agent-tools-org/ai-dispatch install_dir=${AID_INSTALL_DIR:-$HOME/.cargo/bin} fail() { echo "aid install: $*" >&2 exit 1 } command -v curl >/dev/null 2>&1 || fail 'curl is required' version=${AID_VERSION:-} if [ -z "$version" ]; then latest=$(curl --proto '=https' --tlsv1.2 -fsSL -o /dev/null -w '%{url_effective}' \ "https://github.com/$repo/releases/latest") || fail 'cannot resolve the latest release' case "$latest" in "https://github.com/$repo/releases/tag/v"*) version=${latest##*/v} ;; *) fail 'latest release redirect did not resolve to a version tag' ;; esac fi version=${version#v} case "$version" in ''|*[!0-9A-Za-z.+-]*) fail 'AID_VERSION must be a release version, such as 11.0.0' ;; esac case "$(uname -s)" in Linux) target_os=unknown-linux-gnu ;; Darwin) target_os=apple-darwin ;; *) target_os= ;; esac case "$(uname -m)" in x86_64|amd64) target_arch=x86_64 ;; aarch64|arm64) target_arch=aarch64 ;; *) target_arch= ;; esac scratch=$(mktemp -d) || fail 'cannot create temporary directory' install_tmp= trap 'rm -rf "$scratch"; if [ -n "$install_tmp" ]; then rm -f "$install_tmp"; fi' EXIT trap 'exit 1' HUP INT TERM if [ -z "$target_os" ] || [ -z "$target_arch" ]; then echo 'No release binary for this platform; installing with Cargo.' command -v cargo >/dev/null 2>&1 || fail 'unsupported target; install Rust and Cargo first' cargo install ai-dispatch --version "$version" --locked --root "$scratch/cargo" \ || fail 'Cargo installation failed' binary="$scratch/cargo/bin/aid" else command -v tar >/dev/null 2>&1 || fail 'tar is required' asset="aid-v$version-$target_arch-$target_os.tar.gz" base="https://github.com/$repo/releases/download/v$version" echo "Installing aid v$version for $target_arch-$target_os..." curl --proto '=https' --tlsv1.2 -fsSL "$base/$asset" -o "$scratch/$asset" \ || fail "cannot download $asset; check the release and platform" curl --proto '=https' --tlsv1.2 -fsSL "$base/checksums-sha256.txt" -o "$scratch/checksums" \ || fail 'cannot download release checksums' expected=$(awk -v name="$asset" '$2 == name || $2 == "*" name { print $1 }' "$scratch/checksums") [ "${#expected}" = 64 ] || fail 'missing or ambiguous release checksum' case "$expected" in *[!0-9a-fA-F]*) fail 'invalid release checksum' ;; esac if command -v sha256sum >/dev/null 2>&1; then actual=$(sha256sum "$scratch/$asset") elif command -v shasum >/dev/null 2>&1; then actual=$(shasum -a 256 "$scratch/$asset") else fail 'sha256sum or shasum is required' fi actual=${actual%% *} [ "$actual" = "$expected" ] || fail 'SHA-256 mismatch; refusing installation' member="${asset%.tar.gz}/aid" tar -xzf "$scratch/$asset" -C "$scratch" "$member" || fail 'release archive has no aid binary' binary="$scratch/$member" fi [ -f "$binary" ] && [ ! -L "$binary" ] || fail 'invalid aid binary in archive' mkdir -p "$install_dir" || fail "cannot create $install_dir" install_tmp=$(mktemp "$install_dir/.aid.XXXXXX") || fail 'cannot create temporary binary' cp "$binary" "$install_tmp" || fail "cannot write $install_dir/aid" chmod 755 "$install_tmp" if [ "$target_os" = apple-darwin ] && command -v codesign >/dev/null 2>&1; then codesign --force --sign - "$install_tmp" || fail 'macOS ad hoc signing failed' fi mv -f "$install_tmp" "$install_dir/aid" || fail "cannot replace $install_dir/aid" install_tmp= echo "Installed aid v$version to $install_dir/aid" case ":$PATH:" in *":$install_dir:"*) ;; *) echo "Warning: $install_dir is not on PATH. Add it to your shell configuration." >&2 ;; esac echo 'Next: aid setup'