#!/usr/bin/env sh set -e # --- Utilities --- have_cmd() { command -v "$1" >/dev/null 2>&1; } info() { printf "\033[1;34m ==>\033[0m %s\n" "$1"; } ok() { printf "\033[1;32m ==>\033[0m %s\n" "$1"; } warn() { printf "\033[1;33m [WARN]\033[0m %s\n" "$1"; } fail() { printf "\033[1;31m [ERROR]\033[0m %s\n" "$1"; exit 1; } # --- Platform detection --- OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Linux) OS="linux" ;; Darwin) OS="darwin" ;; *) fail "Unsupported operating system: $OS Policate currently supports Linux (x86_64, ARM64) and macOS (x86_64, ARM64). For Windows, use WSL2 or 'npm install -g @policate/cli'." ;; esac case "$ARCH" in x86_64|amd64) ARCH="x64" ;; aarch64|arm64) ARCH="arm64" ;; *) fail "Unsupported architecture: $ARCH Policate currently supports x86_64 and ARM64." ;; esac ARTIFACT="policate-$OS-$ARCH" info "Detected platform: $OS-$ARCH" # --- Determine install directory --- if [ -d "$HOME/.local/bin" ] && echo ":$PATH:" | grep -q ":$HOME/.local/bin:"; then INSTALL_DIR="$HOME/.local/bin" elif command -v sudo >/dev/null 2>&1 && [ -w "/usr/local/bin" ]; then INSTALL_DIR="/usr/local/bin" elif [ -d "$HOME/.local/bin" ]; then INSTALL_DIR="$HOME/.local/bin" warn "$HOME/.local/bin is not in your PATH. Add it to your shell config: export PATH="$HOME/.local/bin:$PATH"" else INSTALL_DIR="$HOME/.local/bin" mkdir -p "$INSTALL_DIR" warn "$HOME/.local/bin is not in your PATH. Add it to your shell config: export PATH="$HOME/.local/bin:$PATH"" fi BINARY_PATH="$INSTALL_DIR/policate" if [ -f "$BINARY_PATH" ]; then info "Existing policate binary found at $BINARY_PATH, will overwrite" fi # --- Detect download tool --- if have_cmd curl; then DL_CMD="curl -sSfL" elif have_cmd wget; then DL_CMD="wget -qO-" else fail "Neither curl nor wget found. Install one of them and try again." fi # --- Resolve first-party public release artifacts --- RELEASE_BASE="https://policate.marcllort.com/releases/latest" DOWNLOAD_URL="$RELEASE_BASE/$ARTIFACT" CHECKSUM_URL="$RELEASE_BASE/checksums" VERSION="latest" SKIP_CHECKSUM=0 info "Using Policate public release mirror: $RELEASE_BASE" # --- Download binary --- TMP_DIR=$(mktemp -d) trap 'rm -rf "$TMP_DIR"' EXIT TMP_BINARY="$TMP_DIR/$ARTIFACT" TMP_CHECKSUM="$TMP_DIR/checksums.txt" info "Downloading $ARTIFACT..." $DL_CMD "$DOWNLOAD_URL" > "$TMP_BINARY" || fail "Download failed: $DOWNLOAD_URL" # --- Verify SHA256 checksum --- if [ "$SKIP_CHECKSUM" = "0" ]; then info "Downloading checksums..." $DL_CMD "$CHECKSUM_URL" > "$TMP_CHECKSUM" 2>/dev/null || warn "Could not fetch checksums.txt, skipping verification." if [ -f "$TMP_CHECKSUM" ] && [ -s "$TMP_CHECKSUM" ]; then EXPECTED_SHA256=$(grep "$ARTIFACT" "$TMP_CHECKSUM" | awk '{print $1}') if [ -n "$EXPECTED_SHA256" ]; then if have_cmd sha256sum; then COMPUTED_SHA256=$(sha256sum "$TMP_BINARY" | awk '{print $1}') elif have_cmd shasum; then COMPUTED_SHA256=$(shasum -a 256 "$TMP_BINARY" | awk '{print $1}') else warn "No SHA256 tool found (sha256sum or shasum). Skipping checksum verification." COMPUTED_SHA256="" fi if [ -n "$COMPUTED_SHA256" ]; then if [ "$COMPUTED_SHA256" = "$EXPECTED_SHA256" ]; then ok "SHA256 checksum verified" else fail "SHA256 checksum mismatch! Expected: $EXPECTED_SHA256 Got: $COMPUTED_SHA256 The downloaded binary may be corrupted or tampered with. Aborting installation." fi fi else warn "No checksum found for $ARTIFACT in checksums.txt. Skipping verification." fi fi fi # --- Install binary --- mkdir -p "$INSTALL_DIR" cp "$TMP_BINARY" "$BINARY_PATH" || fail "Failed to copy binary to $BINARY_PATH" chmod +x "$BINARY_PATH" || fail "Failed to make binary executable" ok "Policate $VERSION installed successfully at $BINARY_PATH" # --- Verify --- if "$BINARY_PATH" --version >/dev/null 2>&1; then INSTALLED_VERSION=$("$BINARY_PATH" --version 2>&1) ok "Installed version: $INSTALLED_VERSION" else warn "Binary installed but --version check failed." fi echo "" info "To get started, run: policate login " info "Or use it directly: policate "your prompt here" " info "Need help? Visit https://policate.marcllort.com/docs"