Files
2026-05-23 15:35:24 -07:00

228 lines
5.4 KiB
Bash

#!/bin/sh
set -eu
REPO_GIT_URL="git+https://github.com/Alishahryar1/free-claude-code.git"
PYTHON_VERSION="3.14.0"
UV_INSTALL_URL="https://astral.sh/uv/install.sh"
dry_run=0
voice_nim=0
voice_local=0
voice_all=0
torch_backend=""
show_usage() {
cat <<'USAGE'
Usage: install.sh [options]
Installs Claude Code if missing, installs or updates uv, Python 3.14.0, and Free Claude Code.
Options:
--voice-nim Install NVIDIA NIM voice transcription support.
--voice-local Install local Whisper voice transcription support.
--voice-all Install all voice transcription backends.
--torch-backend VALUE Use a uv PyTorch backend, such as cu130. Requires local voice.
--dry-run Print commands without running them.
--help Show this help text.
USAGE
}
fail() {
printf 'error: %s\n' "$*" >&2
exit 1
}
step() {
printf '\n==> %s\n' "$1"
}
quote_arg() {
case "$1" in
*[!A-Za-z0-9_./:@%+=,-]*|"")
escaped=$(printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g')
printf '"%s"' "$escaped"
;;
*)
printf '%s' "$1"
;;
esac
}
print_command() {
printf '+'
for arg in "$@"; do
printf ' '
quote_arg "$arg"
done
printf '\n'
}
run() {
print_command "$@"
if [ "$dry_run" -eq 0 ]; then
"$@"
fi
}
run_uv_installer() {
printf '+ curl -LsSf %s | sh\n' "$UV_INSTALL_URL"
if [ "$dry_run" -eq 0 ]; then
command -v curl >/dev/null 2>&1 || fail "curl is required to install uv."
curl -LsSf "$UV_INSTALL_URL" | sh
fi
}
add_path_entry() {
[ -n "$1" ] || return 0
case ":$PATH:" in
*":$1:"*) ;;
*) PATH="$1:$PATH" ;;
esac
}
add_uv_to_path() {
if [ -n "${XDG_BIN_HOME:-}" ]; then
add_path_entry "$XDG_BIN_HOME"
fi
if [ -n "${HOME:-}" ]; then
add_path_entry "$HOME/.local/bin"
add_path_entry "$HOME/.cargo/bin"
fi
export PATH
}
require_command() {
if [ "$dry_run" -eq 0 ] && ! command -v "$1" >/dev/null 2>&1; then
fail "$1 is required. Install it first, then rerun this installer."
fi
}
install_claude_if_missing() {
if command -v claude >/dev/null 2>&1; then
printf 'Claude Code already found on PATH; skipping install.\n'
return 0
fi
require_command npm
run npm install -g @anthropic-ai/claude-code
}
install_or_update_uv() {
add_uv_to_path
if command -v uv >/dev/null 2>&1; then
run uv self update
return 0
fi
run_uv_installer
add_uv_to_path
if [ "$dry_run" -eq 0 ] && ! command -v uv >/dev/null 2>&1; then
fail "uv was installed, but it is not available on PATH. Open a new terminal or add uv's bin directory to PATH."
fi
}
parse_args() {
while [ "$#" -gt 0 ]; do
case "$1" in
--voice-nim)
voice_nim=1
;;
--voice-local)
voice_local=1
;;
--voice-all)
voice_all=1
;;
--torch-backend)
shift
[ "$#" -gt 0 ] || fail "--torch-backend requires a value."
torch_backend="$1"
[ -n "$torch_backend" ] || fail "--torch-backend requires a non-empty value."
;;
--torch-backend=*)
torch_backend="${1#*=}"
[ -n "$torch_backend" ] || fail "--torch-backend requires a non-empty value."
;;
--dry-run)
dry_run=1
;;
--help|-h)
show_usage
exit 0
;;
*)
show_usage >&2
fail "unknown option: $1"
;;
esac
shift
done
}
validate_args() {
include_local=$voice_local
if [ "$voice_all" -eq 1 ]; then
include_local=1
fi
if [ -n "$torch_backend" ] && [ "$include_local" -ne 1 ]; then
fail "--torch-backend requires --voice-local or --voice-all."
fi
}
package_spec() {
include_nim=$voice_nim
include_local=$voice_local
if [ "$voice_all" -eq 1 ]; then
include_nim=1
include_local=1
fi
if [ -n "$torch_backend" ] && [ "$include_local" -ne 1 ]; then
fail "--torch-backend requires --voice-local or --voice-all."
fi
if [ "$include_nim" -eq 1 ] && [ "$include_local" -eq 1 ]; then
printf 'free-claude-code[voice,voice_local] @ %s' "$REPO_GIT_URL"
elif [ "$include_nim" -eq 1 ]; then
printf 'free-claude-code[voice] @ %s' "$REPO_GIT_URL"
elif [ "$include_local" -eq 1 ]; then
printf 'free-claude-code[voice_local] @ %s' "$REPO_GIT_URL"
else
printf '%s' "$REPO_GIT_URL"
fi
}
install_free_claude_code() {
spec=$(package_spec)
if [ -n "$torch_backend" ]; then
run uv tool install --force --torch-backend "$torch_backend" "$spec"
else
run uv tool install --force "$spec"
fi
}
parse_args "$@"
validate_args
step "Installing Claude Code if missing"
install_claude_if_missing
step "Installing uv if missing, updating if present"
install_or_update_uv
step "Installing Python $PYTHON_VERSION"
run uv python install "$PYTHON_VERSION"
step "Installing or updating Free Claude Code"
install_free_claude_code
printf '\nFree Claude Code is installed. Start the proxy with: fcc-server\n'