#!/usr/bin/env bash set -euo pipefail GITHUB_REPO="PromptForcePrime/readybase-public" BASE_URL="https://github.com/${GITHUB_REPO}/releases/latest/download" INSTALL_DIR="${HOME}/.readybase" # ── Colours ───────────────────────────────────────────────────────────────── if [ -t 1 ]; then BOLD="\033[1m"; GREEN="\033[0;32m"; YELLOW="\033[0;33m"; RED="\033[0;31m"; RESET="\033[0m" else BOLD=""; GREEN=""; YELLOW=""; RED=""; RESET="" fi info() { printf "${GREEN}==>${RESET} %s\n" "$*"; } warn() { printf "${YELLOW}warn:${RESET} %s\n" "$*"; } die() { printf "${RED}error:${RESET} %s\n" "$*" >&2; exit 1; } heading() { printf "\n${BOLD}%s${RESET}\n" "$*"; } # ── Platform detection ────────────────────────────────────────────────────── OS=$(uname -s | tr '[:upper:]' '[:lower:]') case "$OS" in darwin) ;; linux) ;; *) die "Unsupported OS: $(uname -s). ReadyBase supports macOS and Linux." ;; esac ARCH=$(uname -m) case "$ARCH" in x86_64) ARCH="amd64" ;; arm64|aarch64) ARCH="arm64" ;; *) die "Unsupported architecture: $(uname -m)" ;; esac heading "Installing ReadyBase (${OS}/${ARCH})" # ── Install binary ────────────────────────────────────────────────────────── BINARY_NAME="readybase-${OS}-${ARCH}" BINARY_URL="${BASE_URL}/${BINARY_NAME}" if [ -w /usr/local/bin ]; then BIN_DIR="/usr/local/bin" else BIN_DIR="${HOME}/bin" mkdir -p "$BIN_DIR" case ":$PATH:" in *":${BIN_DIR}:"*) ;; *) warn "Add ${BIN_DIR} to your PATH: export PATH=\"${BIN_DIR}:\$PATH\"" ;; esac export PATH="${BIN_DIR}:${PATH}" fi DEST="${BIN_DIR}/readybase" info "Downloading ${BINARY_NAME}..." mkdir -p "${INSTALL_DIR}" curl -fsSL "${BINARY_URL}" -o "${DEST}.tmp" # SHA256 checksum verification CHECKSUM_URL="${BASE_URL}/${BINARY_NAME}.sha256" EXPECTED_SHA=$(curl -fsSL "$CHECKSUM_URL" 2>/dev/null | awk '{print $1}' || true) if [ -n "$EXPECTED_SHA" ]; then if command -v shasum &>/dev/null; then ACTUAL_SHA=$(shasum -a 256 "${DEST}.tmp" | awk '{print $1}') elif command -v sha256sum &>/dev/null; then ACTUAL_SHA=$(sha256sum "${DEST}.tmp" | awk '{print $1}') else ACTUAL_SHA="" fi if [ -n "$ACTUAL_SHA" ] && [ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]; then rm -f "${DEST}.tmp" die "SHA256 mismatch! Expected ${EXPECTED_SHA}, got ${ACTUAL_SHA}." fi info "SHA256 verified" fi chmod +x "${DEST}.tmp" mv "${DEST}.tmp" "$DEST" info "Installed readybase -> ${DEST}" # ── Configure Claude Code MCP server ──────────────────────────────────────── CLAUDE_SETTINGS="${HOME}/.claude/settings.json" configure_mcp() { if ! command -v python3 &>/dev/null; then warn "python3 not found, configure MCP server manually" echo " Add to ~/.claude/settings.json:" echo ' {"mcpServers": {"readybase": {"command": "readybase", "args": ["mcp"]}}}' return fi python3 -c " import json, os path = '$CLAUDE_SETTINGS' os.makedirs(os.path.dirname(path), exist_ok=True) try: with open(path) as f: cfg = json.load(f) except (FileNotFoundError, json.JSONDecodeError): cfg = {} mcp = cfg.setdefault('mcpServers', {}) if 'readybase' not in mcp: mcp['readybase'] = {'command': 'readybase', 'args': ['mcp']} with open(path, 'w') as f: json.dump(cfg, f, indent=2) print('Configured ReadyBase MCP server in Claude Code settings.') else: print('ReadyBase MCP server already configured.') " } echo "" printf " ${BOLD}Configure Claude Code MCP integration?${RESET}\n" echo " This adds ReadyBase as an MCP tool server in ~/.claude/settings.json." echo " Claude Code will have access to: readybase_explore (start here)," echo " readybase_relate (blast radius + deps), readybase_story (history + authors)," echo " and the full toolset (score, coverage, convention, ownership, and more)." echo "" printf " Configure? [Y/n] " if [ ! -t 0 ]; then echo "y (non-interactive)" REPLY="y" else read -r REPLY fi case "${REPLY:-y}" in [Yy]*|"") configure_mcp ;; *) echo " Skipped. You can configure later by running: readybase setup " ;; esac # ── Run first scan ────────────────────────────────────────────────────────── echo "" printf " ${BOLD}Run first scan on current directory?${RESET}\n" echo " This analyzes your codebase and generates AI-readiness score + context files." echo "" printf " Scan now? [Y/n] " if [ ! -t 0 ]; then echo "y (non-interactive)" REPLY="y" else read -r REPLY fi case "${REPLY:-y}" in [Yy]*|"") info "Running readybase scan..." readybase scan . || warn "Scan failed (non-fatal), run manually: readybase scan " ;; *) echo " Skipped. Run later: readybase scan " ;; esac # ── Optional: install Prefex ──────────────────────────────────────────────── echo "" printf " ${BOLD}Also install Prefex cost optimizer?${RESET}\n" echo " Prefex reduces Claude Code API costs by 40-70%% via intelligent routing + caching." echo " Free for 30 days, renew with email." echo "" printf " Install Prefex? [Y/n] " if [ ! -t 0 ]; then echo "y (non-interactive)" REPLY="y" else read -r REPLY fi case "${REPLY:-y}" in [Yy]*|"") info "Installing Prefex..." curl -fsSL https://promptforce.ai/install.sh | bash ;; *) echo " Skipped. Install later: readybase save start" ;; esac # ── Done ──────────────────────────────────────────────────────────────────── heading "ReadyBase installed successfully" echo "" echo " Commands:" echo " readybase scan Analyze codebase AI-readiness" echo " readybase go Run everything (scan + setup + index + probe)" echo " readybase probe Generate adversarial tests" echo " readybase save start Start Prefex cost optimizer" echo " readybase serve Launch dashboard at localhost:8765" echo " readybase usage Show agent tool usage + guard compliance" echo "" echo " Dashboard: readybase serve (then open localhost:8765)" echo " Uninstall: rm $(which readybase) && rm -rf ~/.readybase" echo ""