#!/usr/bin/env bash # Grok Build Remote — desktop agent installer # Brand: Grok Build Remote (Linespotting Org) # Usage: # curl -fsSL https://grokbuildremote.com/install.sh | bash # # or local / mirrored: # curl -fsSL https://YOUR_HOST/install.sh | bash # # Downloads agent binaries from GitHub Releases: # LinespottingOrg/GrokBuildRemote-Agents # # PRIVATE REPO NOTE # ----------------- # That repository is private company IP. Public anonymous downloads will fail # until a public release mirror exists. Options: # 1) Export GITHUB_TOKEN or GH_TOKEN with contents:read on the repo, then re-run. # 2) Download the release asset manually from GitHub UI and place it on PATH. # 3) Later: point RELEASE_BASE at a public mirror (S3/R2/Pages) without changing UX. # # Never commit tokens. Never pipe untrusted scripts as root without reading them. # Prefer: # curl -fsSL .../install.sh -o install-gbr.sh && less install-gbr.sh && bash install-gbr.sh set -euo pipefail REPO="${GBR_REPO:-LinespottingOrg/GrokBuildRemote-Agents}" INSTALL_DIR="${GBR_INSTALL_DIR:-${HOME}/.local/bin}" BIN_NAME="${GBR_BIN_NAME:-gbr-agent}" VERSION="${GBR_VERSION:-latest}" TMPDIR="${TMPDIR:-/tmp}" WORKDIR="$(mktemp -d "${TMPDIR%/}/gbr-install.XXXXXX")" cleanup() { rm -rf "${WORKDIR}"; } trap cleanup EXIT log() { printf '==> %s\n' "$*"; } warn() { printf '!! %s\n' "$*" >&2; } die() { printf 'error: %s\n' "$*" >&2; exit 1; } # --- detect OS / arch --- OS="$(uname -s | tr '[:upper:]' '[:lower:]')" ARCH="$(uname -m)" case "${ARCH}" in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64) ARCH="arm64" ;; armv7l) ARCH="armv7" ;; *) die "unsupported architecture: ${ARCH}" ;; esac case "${OS}" in linux) PLATFORM="linux" ;; darwin) PLATFORM="darwin" ;; msys*|mingw*|cygwin*) PLATFORM="windows" ;; *) # Git Bash on Windows often reports MINGW / MSYS if [[ "${OS}" == *"mingw"* || "${OS}" == *"msys"* || "${OS}" == *"cygwin"* ]]; then PLATFORM="windows" else die "unsupported OS: ${OS} (use WSL/Git Bash on Windows, or download the .exe from releases)" fi ;; esac EXT="" ASSET_OS="${PLATFORM}" if [[ "${PLATFORM}" == "windows" ]]; then EXT=".exe" fi # Expected asset naming (adjust when CI release names stabilize): # gbr-agent-linux-amd64 # gbr-agent-darwin-arm64 # gbr-agent-windows-amd64.exe ASSET_NAME="${BIN_NAME}-${ASSET_OS}-${ARCH}${EXT}" log "Grok Build Remote agent installer" log "platform=${ASSET_OS} arch=${ARCH} version=${VERSION}" log "repo=${REPO} asset=${ASSET_NAME}" # --- auth header if token present --- AUTH_ARGS=() TOKEN="${GITHUB_TOKEN:-${GH_TOKEN:-}}" if [[ -n "${TOKEN}" ]]; then AUTH_ARGS=(-H "Authorization: Bearer ${TOKEN}") log "using GitHub token from environment (not logged)" else warn "No GITHUB_TOKEN/GH_TOKEN set." warn "Private releases require a token with contents:read, or a public mirror." fi api() { local url="$1" curl -fsSL \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "${AUTH_ARGS[@]}" \ "${url}" } # --- resolve release JSON --- if [[ "${VERSION}" == "latest" ]]; then API_URL="https://api.github.com/repos/${REPO}/releases/latest" else API_URL="https://api.github.com/repos/${REPO}/releases/tags/${VERSION}" fi log "fetching release metadata…" if ! RELEASE_JSON="$(api "${API_URL}" 2>"${WORKDIR}/api.err")"; then warn "GitHub API request failed." if [[ -f "${WORKDIR}/api.err" ]]; then sed 's/^/ /' "${WORKDIR}/api.err" >&2 || true fi cat >&2 </dev/null 2>&1; then download_url="$(printf '%s' "${RELEASE_JSON}" | jq -r --arg n "${ASSET_NAME}" '.assets[] | select(.name==$n) | .url' | head -n1)" # API asset URL requires Accept: application/octet-stream for private assets browser_url="$(printf '%s' "${RELEASE_JSON}" | jq -r --arg n "${ASSET_NAME}" '.assets[] | select(.name==$n) | .browser_download_url' | head -n1)" else # fragile fallback: extract browser_download_url lines containing asset name browser_url="$(printf '%s' "${RELEASE_JSON}" | tr ',' '\n' | grep -o "https://[^\"]*${ASSET_NAME}" | head -n1 || true)" download_url="" fi OUT="${WORKDIR}/${ASSET_NAME}" if [[ -n "${GBR_RELEASE_BASE:-}" ]]; then # Public mirror override (no GitHub API) MIRROR_URL="${GBR_RELEASE_BASE%/}/${VERSION}/${ASSET_NAME}" if [[ "${VERSION}" == "latest" ]]; then MIRROR_URL="${GBR_RELEASE_BASE%/}/latest/${ASSET_NAME}" fi log "downloading from mirror: ${MIRROR_URL}" curl -fsSL -o "${OUT}" "${MIRROR_URL}" || die "mirror download failed" elif [[ -n "${download_url}" && -n "${TOKEN}" ]]; then log "downloading private asset via API…" curl -fsSL \ -H "Accept: application/octet-stream" \ -H "Authorization: Bearer ${TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ -o "${OUT}" \ "${download_url}" || die "asset download failed" elif [[ -n "${browser_url}" ]]; then log "downloading: ${browser_url}" curl -fsSL "${AUTH_ARGS[@]}" -o "${OUT}" "${browser_url}" || die "asset download failed" else die "asset '${ASSET_NAME}' not found in release. Publish a matching binary or set GBR_RELEASE_BASE." fi [[ -s "${OUT}" ]] || die "downloaded file is empty" mkdir -p "${INSTALL_DIR}" TARGET="${INSTALL_DIR}/${BIN_NAME}${EXT}" install -m 0755 "${OUT}" "${TARGET}" 2>/dev/null || { cp "${OUT}" "${TARGET}" chmod 0755 "${TARGET}" || true } log "installed: ${TARGET}" # PATH hint case ":${PATH}:" in *":${INSTALL_DIR}:"*) ;; *) warn "Add to PATH if needed:" warn " export PATH=\"${INSTALL_DIR}:\$PATH\"" ;; esac cat <