| #!/usr/bin/env bash |
| set -euo pipefail |
|
|
| |
| |
|
|
| RED='\033[0;31m' |
| GREEN='\033[0;32m' |
| YELLOW='\033[1;33m' |
| CYAN='\033[0;36m' |
| BOLD='\033[1m' |
| DIM='\033[2m' |
| RESET='\033[0m' |
|
|
| REPO="https://github.com/paoloanzn/free-code.git" |
| INSTALL_DIR="$HOME/free-code" |
| BUN_MIN_VERSION="1.3.11" |
|
|
| info() { printf "${CYAN}[*]${RESET} %s\n" "$*"; } |
| ok() { printf "${GREEN}[+]${RESET} %s\n" "$*"; } |
| warn() { printf "${YELLOW}[!]${RESET} %s\n" "$*"; } |
| fail() { |
| printf "${RED}[x]${RESET} %s\n" "$*" |
| exit 1 |
| } |
|
|
| header() { |
| echo "" |
| printf "${BOLD}${CYAN}" |
| cat <<'ART' |
| ___ _ |
| / _|_ __ ___ ___ ___ __| | ___ |
| | |_| '__/ _ \/ _ \_____ / __/ _` |/ _ \ |
| | _| | | __/ __/_____| (_| (_| | __/ |
| |_| |_| \___|\___| \___\__,_|\___| |
| |
| ART |
| printf "${RESET}" |
| printf "${DIM} The free build of Claude Code${RESET}\n" |
| echo "" |
| } |
| |
| # ------------------------------------------------------------------- |
| # System checks |
| # ------------------------------------------------------------------- |
| |
| check_os() { |
| case "$(uname -s)" in |
| Darwin) OS="macos" ;; |
| Linux) OS="linux" ;; |
| *) fail "Unsupported OS: $(uname -s). macOS or Linux required." ;; |
| esac |
| ok "OS: $(uname -s) $(uname -m)" |
| } |
| |
| check_git() { |
| if ! command -v git &>/dev/null; then |
| fail "git is not installed. Install it first: |
| macOS: xcode-select --install |
| Linux: sudo apt install git (or your distro's equivalent)" |
| fi |
| ok "git: $(git --version | head -1)" |
| } |
| |
| # Compare semver: returns 0 if $1 >= $2 |
| version_gte() { |
| [ "$(printf '%s\n' "$1" "$2" | sort -V | head -1)" = "$2" ] |
| } |
| |
| check_bun() { |
| if command -v bun &>/dev/null; then |
| local ver |
| ver="$(bun --version 2>/dev/null || echo "0.0.0")" |
| if version_gte "$ver" "$BUN_MIN_VERSION"; then |
| ok "bun: v${ver}" |
| return |
| fi |
| warn "bun v${ver} found but v${BUN_MIN_VERSION}+ required. Upgrading..." |
| else |
| info "bun not found. Installing..." |
| fi |
| install_bun |
| } |
| |
| install_bun() { |
| curl -fsSL https://bun.sh/install | bash |
| # Source the updated profile so bun is on PATH for this session |
| export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}" |
| export PATH="$BUN_INSTALL/bin:$PATH" |
| if ! command -v bun &>/dev/null; then |
| fail "bun installation succeeded but binary not found on PATH. |
| Add this to your shell profile and restart: |
| export PATH=\"\$HOME/.bun/bin:\$PATH\"" |
| fi |
| ok "bun: v$(bun --version) (just installed)" |
| } |
| |
| # ------------------------------------------------------------------- |
| # Clone & build |
| # ------------------------------------------------------------------- |
| |
| clone_repo() { |
| if [ -d "$INSTALL_DIR" ]; then |
| warn "$INSTALL_DIR already exists" |
| if [ -d "$INSTALL_DIR/.git" ]; then |
| info "Pulling latest changes..." |
| git -C "$INSTALL_DIR" pull --ff-only origin main 2>/dev/null || { |
| warn "Pull failed, continuing with existing copy" |
| } |
| fi |
| else |
| info "Cloning repository..." |
| git clone --depth 1 "$REPO" "$INSTALL_DIR" |
| fi |
| ok "Source: $INSTALL_DIR" |
| } |
| |
| install_deps() { |
| info "Installing dependencies..." |
| cd "$INSTALL_DIR" |
| bun install --frozen-lockfile 2>/dev/null || bun install |
| ok "Dependencies installed" |
| } |
| |
| build_binary() { |
| info "Building free-code (all experimental features enabled)..." |
| cd "$INSTALL_DIR" |
| bun run build:dev:full |
| ok "Binary built: $INSTALL_DIR/cli-dev" |
| } |
| |
| link_binary() { |
| local link_dir="$HOME/.local/bin" |
| mkdir -p "$link_dir" |
| |
| ln -sf "$INSTALL_DIR/cli-dev" "$link_dir/free-code" |
| ok "Symlinked: $link_dir/free-code" |
| |
| if ! echo "$PATH" | tr ':' '\n' | grep -qx "$link_dir"; then |
| warn "$link_dir is not on your PATH" |
| echo "" |
| printf "${YELLOW} Add this to your shell profile (~/.bashrc, ~/.zshrc, etc.):${RESET}\n" |
| printf "${BOLD} export PATH=\"\$HOME/.local/bin:\$PATH\"${RESET}\n" |
| echo "" |
| fi |
| } |
| |
| # ------------------------------------------------------------------- |
| # Main |
| # ------------------------------------------------------------------- |
| |
| header |
| info "Starting installation..." |
| echo "" |
| |
| check_os |
| check_git |
| check_bun |
| echo "" |
| |
| clone_repo |
| install_deps |
| build_binary |
| link_binary |
| |
| echo "" |
| printf "${GREEN}${BOLD} Installation complete!${RESET}\n" |
| echo "" |
| printf " ${BOLD}Run it:${RESET}\n" |
| printf " ${CYAN}free-code${RESET} |
| printf " ${CYAN}free-code -p \"your prompt\"${RESET} # one-shot mode\n" |
| echo "" |
| printf " ${BOLD}Set your API key:${RESET}\n" |
| printf " ${CYAN}export ANTHROPIC_API_KEY=\"sk-ant-...\"${RESET}\n" |
| echo "" |
| printf " ${BOLD}Or log in with Claude.ai:${RESET}\n" |
| printf " ${CYAN}free-code /login${RESET}\n" |
| echo "" |
| printf " ${DIM}Source: $INSTALL_DIR${RESET}\n" |
| printf " ${DIM}Binary: $INSTALL_DIR/cli-dev${RESET}\n" |
| printf " ${DIM}Link: ~/.local/bin/free-code${RESET}\n" |
| echo "" |
|
|