#!/bin/sh # stackplay installer — https://stackplay.run # Usage: curl -fsSL https://stackplay.run | sh # # Environment variables: # STACKPLAY_VERSION Pin a specific version (e.g. "0.3.0" or "v0.3.0") # STACKPLAY_INSTALL_DIR Override install directory (default: ~/.local/bin) # STACKPLAY_QUIET Set to 1 to suppress non-error output set -eu #region helpers BOLD="" DIM="" GREEN="" CYAN="" RED="" YELLOW="" RESET="" setup_colors() { if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then BOLD="\033[1m" DIM="\033[2m" GREEN="\033[32m" CYAN="\033[36m" RED="\033[31m" YELLOW="\033[33m" RESET="\033[0m" fi } info() { if [ -z "${STACKPLAY_QUIET:-}" ]; then printf "${DIM}%s${RESET}\n" "$1" >&2 fi } success() { printf "${GREEN}%s${RESET}\n" "$1" >&2 } error() { printf "${RED}error:${RESET} %s\n" "$1" >&2 exit 1 } warn() { printf "${YELLOW}warning:${RESET} %s\n" "$1" >&2 } command_exists() { command -v "$1" >/dev/null 2>&1 } #endregion #region platform detection detect_platform() { OS="$(uname -s)" case "$OS" in Darwin) OS="darwin" ;; Linux) OS="linux" ;; MINGW*|MSYS*|CYGWIN*) error "Windows is not yet supported. Track progress at https://github.com/saulsharma/stackplay/issues" ;; *) error "Unsupported operating system: $OS" ;; esac ARCH="$(uname -m)" case "$ARCH" in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64) ARCH="arm64" ;; *) error "Unsupported architecture: $ARCH" ;; esac } #endregion #region network fetch() { url="$1" dest="$2" if command_exists curl; then curl -fsSL "$url" -o "$dest" elif command_exists wget; then wget -qO "$dest" "$url" else error "curl or wget is required" fi } fetch_stdout() { url="$1" if command_exists curl; then curl -fsSL "$url" elif command_exists wget; then wget -qO- "$url" else error "curl or wget is required" fi } #endregion #region version resolution resolve_version() { if [ -n "${STACKPLAY_VERSION:-}" ]; then # Strip leading v VERSION="${STACKPLAY_VERSION#v}" TAG="v${VERSION}" return fi info "Finding latest version..." TAG=$(fetch_stdout "https://api.github.com/repos/$REPO/releases/latest" \ | grep '"tag_name"' | head -1 | cut -d'"' -f4) || true if [ -z "$TAG" ]; then error "Could not determine latest version. Set STACKPLAY_VERSION to install a specific version." fi VERSION="${TAG#v}" } #endregion #region checksum verification verify_checksum() { tarball_path="$1" tarball_name="$2" if ! command_exists shasum && ! command_exists sha256sum; then warn "Neither shasum nor sha256sum found — skipping checksum verification" return fi info "Verifying checksum..." checksum_url="$BASE_URL/checksums.txt" checksums=$(fetch_stdout "$checksum_url" 2>/dev/null) || { warn "Could not fetch checksums — skipping verification" return } expected=$(echo "$checksums" | grep "$tarball_name" | head -1 | awk '{print $1}') if [ -z "$expected" ]; then warn "No checksum found for $tarball_name — skipping verification" return fi if command_exists sha256sum; then actual=$(sha256sum "$tarball_path" | awk '{print $1}') else actual=$(shasum -a 256 "$tarball_path" | awk '{print $1}') fi if [ "$expected" != "$actual" ]; then error "Checksum mismatch! Expected: $expected Actual: $actual This could indicate a corrupted download or a tampered release." fi } #endregion #region install install_binaries() { tmp="$1" install_dir="$2" if [ ! -f "$tmp/stackplay" ]; then error "Release archive did not contain the stackplay binary" fi mkdir -p "$install_dir" cp "$tmp/stackplay" "$install_dir/stackplay" chmod +x "$install_dir/stackplay" if [ -f "$tmp/stackplay-tui" ]; then cp "$tmp/stackplay-tui" "$install_dir/stackplay-tui" chmod +x "$install_dir/stackplay-tui" else warn "Release archive did not contain stackplay-tui; CLI installed without the TUI" fi } #endregion #region path helpers shell_name() { basename "${SHELL:-/bin/sh}" } print_path_instructions() { install_dir="$1" # Check if already in PATH case ":${PATH}:" in *":${install_dir}:"*) return ;; esac shell=$(shell_name) printf "\n" warn "$install_dir is not in your PATH" printf "\n" printf " Add it by running:\n\n" case "$shell" in zsh) printf " ${CYAN}echo 'export PATH=\"%s:\$PATH\"' >> ~/.zshrc && source ~/.zshrc${RESET}\n" "$install_dir" ;; bash) rc="~/.bashrc" if [ "$(uname -s)" = "Darwin" ]; then rc="~/.bash_profile" fi printf " ${CYAN}echo 'export PATH=\"%s:\$PATH\"' >> %s && source %s${RESET}\n" "$install_dir" "$rc" "$rc" ;; fish) printf " ${CYAN}fish_add_path %s${RESET}\n" "$install_dir" ;; *) printf " ${CYAN}export PATH=\"%s:\$PATH\"${RESET}\n" "$install_dir" ;; esac printf "\n" } #endregion #region main main() { setup_colors REPO="saulsharma/stackplay" INSTALL_DIR="${STACKPLAY_INSTALL_DIR:-$HOME/.local/bin}" detect_platform info "Platform: ${OS}/${ARCH}" resolve_version info "Version: ${VERSION}" BASE_URL="https://github.com/$REPO/releases/download/$TAG" TARBALL="stackplay_${VERSION}_${OS}_${ARCH}.tar.gz" URL="$BASE_URL/$TARBALL" # Download TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT info "Downloading stackplay ${VERSION}..." fetch "$URL" "$TMP/$TARBALL" # Verify verify_checksum "$TMP/$TARBALL" "$TARBALL" # Extract tar xzf "$TMP/$TARBALL" -C "$TMP" # Install install_binaries "$TMP" "$INSTALL_DIR" # Done printf "\n" success " stackplay ${VERSION} installed to ${INSTALL_DIR}" printf "\n" print_path_instructions "$INSTALL_DIR" printf " ${BOLD}Get started:${RESET}\n\n" printf " ${CYAN}cd your-project${RESET}\n" printf " ${CYAN}stackplay${RESET}\n\n" printf " ${BOLD}Using an AI coding agent?${RESET} Install the stackplay skill for\n" printf " Claude Code, Cursor, Codex, opencode, and others:\n\n" printf " ${CYAN}npx skills add saulsharma/stackplay${RESET}\n\n" printf " ${DIM}https://github.com/saulsharma/stackplay${RESET}\n\n" } main "$@" #endregion