mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-29 21:33:54 +00:00
222 lines
6.6 KiB
Bash
222 lines
6.6 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
APP=tfcode
|
|
GITEA_HOST="${TFCODE_GITEA_HOST:-gitea.toothfairyai.com}"
|
|
GITEA_REPO="${TFCODE_GITEA_REPO:-ToothFairyAI/tfcode}"
|
|
|
|
MUTED='\033[0;2m'
|
|
RED='\033[0;31m'
|
|
ORANGE='\033[38;5;214m'
|
|
GREEN='\033[0;32m'
|
|
NC='\033[0m'
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
tfcode Installer - ToothFairyAI's official coding agent
|
|
|
|
Usage: install.sh [options]
|
|
|
|
Options:
|
|
-h, --help Display this help message
|
|
-v, --version <version> Install a specific version (e.g., 1.0.0)
|
|
--no-modify-path Don't modify shell config files
|
|
|
|
Examples:
|
|
curl -fsSL https://toothfairyai.com/install/tfcode | bash
|
|
curl -fsSL https://toothfairyai.com/install/tfcode | bash -s -- --version 1.0.0
|
|
EOF
|
|
}
|
|
|
|
requested_version=${VERSION:-}
|
|
no_modify_path=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
-v|--version)
|
|
if [[ -n "${2:-}" ]]; then
|
|
requested_version="$2"
|
|
shift 2
|
|
else
|
|
echo -e "${RED}Error: --version requires a version argument${NC}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
--no-modify-path)
|
|
no_modify_path=true
|
|
shift
|
|
;;
|
|
*)
|
|
echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
INSTALL_DIR=$HOME/.tfcode/bin
|
|
mkdir -p "$INSTALL_DIR"
|
|
|
|
# Detect platform
|
|
raw_os=$(uname -s)
|
|
os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]')
|
|
case "$raw_os" in
|
|
Darwin*) os="darwin" ;;
|
|
Linux*) os="linux" ;;
|
|
MINGW*|MSYS*|CYGWIN*) os="windows" ;;
|
|
esac
|
|
|
|
arch=$(uname -m)
|
|
if [[ "$arch" == "aarch64" ]]; then arch="arm64"; fi
|
|
if [[ "$arch" == "x86_64" ]]; then arch="x64"; fi
|
|
|
|
# Check Rosetta on macOS
|
|
if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then
|
|
rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)
|
|
if [ "$rosetta_flag" = "1" ]; then arch="arm64"; fi
|
|
fi
|
|
|
|
# Check AVX2 on x64
|
|
needs_baseline=false
|
|
if [ "$arch" = "x64" ]; then
|
|
if [ "$os" = "linux" ]; then
|
|
if ! grep -qwi avx2 /proc/cpuinfo 2>/dev/null; then
|
|
needs_baseline=true
|
|
fi
|
|
fi
|
|
if [ "$os" = "darwin" ]; then
|
|
avx2=$(sysctl -n hw.optional.avx2_0 2>/dev/null || echo 0)
|
|
if [ "$avx2" != "1" ]; then needs_baseline=true; fi
|
|
fi
|
|
fi
|
|
|
|
# Check musl on Linux
|
|
is_musl=false
|
|
if [ "$os" = "linux" ]; then
|
|
if [ -f /etc/alpine-release ]; then is_musl=true; fi
|
|
if command -v ldd >/dev/null 2>&1; then
|
|
if ldd --version 2>&1 | grep -qi musl; then is_musl=true; fi
|
|
fi
|
|
fi
|
|
|
|
# Build target
|
|
target="$os-$arch"
|
|
if [ "$needs_baseline" = "true" ]; then target="$target-baseline"; fi
|
|
if [ "$is_musl" = "true" ]; then target="$target-musl"; fi
|
|
|
|
archive_ext=".zip"
|
|
if [ "$os" = "linux" ]; then archive_ext=".tar.gz"; fi
|
|
|
|
filename="$APP-$target$archive_ext"
|
|
|
|
# Check tools
|
|
if [ "$os" = "linux" ]; then
|
|
if ! command -v tar >/dev/null 2>&1; then
|
|
echo -e "${RED}Error: 'tar' is required but not installed.${NC}"
|
|
exit 1
|
|
fi
|
|
else
|
|
if ! command -v unzip >/dev/null 2>&1; then
|
|
echo -e "${RED}Error: 'unzip' is required but not installed.${NC}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Get version
|
|
if [ -z "$requested_version" ]; then
|
|
# Get latest version from Gitea API
|
|
api_url="https://$GITEA_HOST/api/v1/repos/$GITEA_REPO/releases/latest"
|
|
specific_version=$(curl -s "$api_url" | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
|
|
|
|
if [[ $? -ne 0 || -z "$specific_version" ]]; then
|
|
echo -e "${RED}Failed to fetch version information${NC}"
|
|
exit 1
|
|
fi
|
|
url="https://$GITEA_HOST/$GITEA_REPO/releases/download/v${specific_version}/$filename"
|
|
else
|
|
requested_version="${requested_version#v}"
|
|
url="https://$GITEA_HOST/$GITEA_REPO/releases/download/v${requested_version}/$filename"
|
|
specific_version=$requested_version
|
|
fi
|
|
|
|
# Download
|
|
echo -e "${MUTED}Installing ${NC}tfcode ${MUTED}version: ${NC}$specific_version"
|
|
tmp_dir="${TMPDIR:-/tmp}/tfcode_install_$$"
|
|
mkdir -p "$tmp_dir"
|
|
|
|
echo -e "${MUTED}Downloading ${NC}$filename"
|
|
curl -# -L -o "$tmp_dir/$filename" "$url"
|
|
|
|
# Extract
|
|
echo -e "${MUTED}Extracting...${NC}"
|
|
if [ "$os" = "linux" ]; then
|
|
tar -xzf "$tmp_dir/$filename" -C "$tmp_dir"
|
|
else
|
|
unzip -q "$tmp_dir/$filename" -d "$tmp_dir"
|
|
fi
|
|
|
|
# Install
|
|
mv "$tmp_dir/tfcode" "$INSTALL_DIR"
|
|
chmod 755 "${INSTALL_DIR}/tfcode"
|
|
rm -rf "$tmp_dir"
|
|
|
|
# Add to PATH
|
|
add_to_path() {
|
|
local config_file=$1
|
|
local command=$2
|
|
|
|
if grep -Fxq "$command" "$config_file" 2>/dev/null; then
|
|
return
|
|
elif [[ -w $config_file ]]; then
|
|
echo -e "\n# tfcode" >> "$config_file"
|
|
echo "$command" >> "$config_file"
|
|
echo -e "${MUTED}Added tfcode to \$PATH in ${NC}$config_file"
|
|
fi
|
|
}
|
|
|
|
if [[ "$no_modify_path" != "true" ]]; then
|
|
current_shell=$(basename "$SHELL")
|
|
case $current_shell in
|
|
fish) config_files="$HOME/.config/fish/config.fish" ;;
|
|
zsh) config_files="$HOME/.zshrc $HOME/.zshenv" ;;
|
|
bash) config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile" ;;
|
|
*) config_files="$HOME/.profile" ;;
|
|
esac
|
|
|
|
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
|
|
for file in $config_files; do
|
|
if [[ -f $file ]]; then
|
|
add_to_path "$file" "export PATH=$INSTALL_DIR:\$PATH"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Install Python SDK
|
|
echo ""
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
echo -e "${MUTED}Installing ToothFairyAI Python SDK...${NC}"
|
|
python3 -m pip install --user --break-system-packages toothfairyai pydantic httpx rich 2>/dev/null || \
|
|
python3 -m pip install --user toothfairyai pydantic httpx rich 2>/dev/null || \
|
|
echo -e "${ORANGE}Could not install Python SDK. Run manually:${NC}"
|
|
echo -e " ${MUTED}pip install toothfairyai pydantic httpx rich${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${GREEN}✓ tfcode installed successfully!${NC}"
|
|
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo ""
|
|
echo -e "${MUTED}Quick Start:${NC}"
|
|
echo ""
|
|
echo -e " ${ORANGE}tfcode setup${NC} ${MUTED}Interactive credential setup${NC}"
|
|
echo -e " ${ORANGE}tfcode validate${NC} ${MUTED}Test your credentials${NC}"
|
|
echo -e " ${ORANGE}tfcode sync${NC} ${MUTED}Sync tools from workspace${NC}"
|
|
echo -e " ${ORANGE}tfcode${NC} ${MUTED}Start coding assistant${NC}"
|
|
echo ""
|
|
echo -e "${MUTED}Documentation: https://toothfairyai.com/developers/tfcode${NC}"
|
|
echo "" |