#!/bin/bash # Mole - Main Entry Point # A comprehensive macOS maintenance tool # # ๐Ÿงน Clean - Remove junk files and optimize system # ๐Ÿ—‘๏ธ Uninstall - Remove applications completely # # Usage: # ./mole # Interactive main menu # ./mole clean # Direct clean mode # ./mole uninstall # Direct uninstall mode # ./mole --help # Show help set -euo pipefail # Get script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Source common functions source "$SCRIPT_DIR/lib/common.sh" # Version info VERSION="1.3.0" MOLE_TAGLINE="can dig deep to clean your Mac." # Check for updates (non-blocking, cached) check_for_updates() { local cache_dir="$HOME/.cache/mole" local version_cache="$cache_dir/version_check" local check_interval=86400 # Check once per day (24 hours) mkdir -p "$cache_dir" 2>/dev/null # Check if we should run version check (based on cache age) if [[ -f "$version_cache" ]]; then local cache_age=$(($(date +%s) - $(stat -f%m "$version_cache" 2>/dev/null || echo 0))) if [[ $cache_age -lt $check_interval ]]; then # Cache is still fresh, show cached message if exists if [[ -s "$version_cache" ]]; then cat "$version_cache" fi return 0 fi fi # Run version check in background (non-blocking) ( local latest_version="" local timeout=3 # 3 second timeout for version check # Try to fetch latest version from GitHub with timeout if command -v curl >/dev/null 2>&1; then latest_version=$(curl -fsSL --connect-timeout 2 --max-time $timeout \ "https://api.github.com/repos/tw93/mole/releases/latest" 2>/dev/null | \ grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^[Vv]//') elif command -v wget >/dev/null 2>&1; then latest_version=$(wget -qO- --timeout=$timeout --tries=1 \ "https://api.github.com/repos/tw93/mole/releases/latest" 2>/dev/null | \ grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^[Vv]//') fi # Compare versions if fetch succeeded if [[ -n "$latest_version" && "$latest_version" != "$VERSION" ]]; then # Version mismatch - cache the update message local msg="${YELLOW}๐Ÿ“ข New version available: ${GREEN}${latest_version}${YELLOW} (current: ${VERSION})${NC}\n Run ${GREEN}mole update${YELLOW} to upgrade${NC}" echo -e "$msg" > "$version_cache" echo -e "$msg" else # Up to date or check failed - clear cache echo "" > "$version_cache" fi # Touch cache file to update timestamp touch "$version_cache" 2>/dev/null ) & # Don't wait for background check disown 2>/dev/null || true } show_brand_banner() { cat << EOF ${GREEN} __ __ _ ${NC} ${GREEN}| \/ | ___ | | ___ ${NC} ${GREEN}| |\/| |/ _ \| |/ _ \\${NC} ${GREEN}| | | | (_) | | __/${NC} ${BLUE}https://github.com/tw93/mole${NC} ${GREEN}|_| |_|\___/|_|\___|${NC} ${GREEN}${MOLE_TAGLINE}${NC} EOF } animate_mole_intro() { # Skip animation if stdout isn't a TTY (non-interactive) if [[ ! -t 1 ]]; then return fi clear_screen printf '\n' hide_cursor local -a mole_lines=() while IFS= read -r line; do mole_lines+=("$line") done <<'EOF' /\_/\ ____/ o o \ /~____ =o= / (______)__m_m) / \ __/ /\ \__ /__/ \__\_ EOF local idx local body_cutoff=4 local body_color="${PURPLE}" local ground_color="${GREEN}" for idx in "${!mole_lines[@]}"; do if (( idx < body_cutoff )); then printf "%s\n" "${body_color}${mole_lines[$idx]}${NC}" else printf "%s\n" "${ground_color}${mole_lines[$idx]}${NC}" fi sleep 0.1 done printf '\n' printf "%s\n" "${BLUE}Ready to dig deep...${NC}" sleep 0.5 printf '\033[2J\033[H' show_cursor } show_version() { printf 'Mole version %s\n' "$VERSION" } show_help() { show_brand_banner echo printf "%s%s%s\n" "$BLUE" "USAGE" "$NC" printf " %s%s%s [command]\n\n" "$GREEN" "mole" "$NC" printf "%s%s%s\n" "$BLUE" "COMMANDS" "$NC" printf " %s%-20s%s %s\n" "$GREEN" "mole" "$NC" "Interactive main menu" printf " %s%-20s%s %s\n" "$GREEN" "mole clean" "$NC" "Deeper system cleanup" printf " %s%-20s%s %s\n" "$GREEN" "mole clean --dry-run" "$NC" "Preview cleanup (no deletions)" printf " %s%-20s%s %s\n" "$GREEN" "mole uninstall" "$NC" "Remove applications completely" printf " %s%-20s%s %s\n" "$GREEN" "mole update" "$NC" "Update Mole to the latest version" printf " %s%-20s%s %s\n" "$GREEN" "mole --version" "$NC" "Show installed version" printf " %s%-20s%s %s\n" "$GREEN" "mole --help" "$NC" "Show this help message" printf "\n%s%s%s\n" "$BLUE" "MORE" "$NC" printf " https://github.com/tw93/mole\n\n" } # Simple update function update_mole() { log_info "Updating Mole..." local installer_url="https://raw.githubusercontent.com/tw93/mole/main/install.sh" local tmp_installer tmp_installer="$(mktemp)" || { log_error "Failed to create temp file"; exit 1; } # Download installer with timeout if command -v curl >/dev/null 2>&1; then if ! curl -fsSL --connect-timeout 10 --max-time 60 "$installer_url" -o "$tmp_installer"; then rm -f "$tmp_installer" log_error "Failed to download installer (network timeout or error)" exit 1 fi elif command -v wget >/dev/null 2>&1; then if ! wget --timeout=10 --tries=3 -qO "$tmp_installer" "$installer_url"; then rm -f "$tmp_installer" log_error "Failed to download installer (network timeout or error)" exit 1 fi else rm -f "$tmp_installer" log_error "Please install curl or wget to update Mole" exit 1 fi chmod +x "$tmp_installer" # Determine install directory local mole_path mole_path="$(command -v mole 2>/dev/null || echo "$0")" local install_dir install_dir="$(cd "$(dirname "$mole_path")" && pwd)" # Run installer if "$tmp_installer" --prefix "$install_dir" --config "$HOME/.config/mole" --update 2>/dev/null; then log_success "Mole updated successfully" else log_warning "Update failed, trying reinstall..." if "$tmp_installer" --prefix "$install_dir" --config "$HOME/.config/mole"; then log_success "Mole reinstalled successfully" else rm -f "$tmp_installer" log_error "Update failed" exit 1 fi fi rm -f "$tmp_installer" } # Display main menu options show_main_menu() { local selected="${1:-1}" local full_draw="${2:-true}" if [[ "$full_draw" == "true" ]]; then clear_screen echo "" show_brand_banner echo "" printf '\033[s' else printf '\033[u\033[0J' fi show_menu_option 1 "Clean System - Remove junk files and optimize" "$([[ $selected -eq 1 ]] && echo true || echo false)" show_menu_option 2 "Uninstall Apps - Remove applications completely" "$([[ $selected -eq 2 ]] && echo true || echo false)" show_menu_option 3 "Help & Information - Usage guide and tips" "$([[ $selected -eq 3 ]] && echo true || echo false)" show_menu_option 4 "Exit - Close Mole" "$([[ $selected -eq 4 ]] && echo true || echo false)" if [[ -t 0 ]]; then echo "" echo -e "${BLUE}โ†‘/โ†“ to navigate, ENTER to select, Q to quit${NC}" fi } # Interactive main menu loop interactive_main_menu() { maybe_show_intro() { if [[ ! -t 1 ]]; then return fi local tty_name tty_name=$(tty 2>/dev/null || echo "") if [[ -n "$tty_name" ]]; then local sanitized sanitized=$(echo "$tty_name" | tr -c '[:alnum:]_' '_') local flag_file="/tmp/mole_intro_${sanitized}" if [[ -f "$flag_file" ]]; then return fi animate_mole_intro touch "$flag_file" 2>/dev/null || true else if [[ -z "${MOLE_INTRO_SHOWN:-}" ]]; then animate_mole_intro export MOLE_INTRO_SHOWN=1 fi fi } maybe_show_intro local current_option=1 local first_draw=true cleanup_and_exit() { show_cursor echo "" echo "Thank you for using Mole!" exit 0 } trap cleanup_and_exit INT hide_cursor while true; do show_main_menu $current_option "$first_draw" if [[ "$first_draw" == "true" ]]; then first_draw=false fi local key=$(read_key) [[ $? -ne 0 ]] && continue case "$key" in "UP") ((current_option > 1)) && ((current_option--)) ;; "DOWN") ((current_option < 4)) && ((current_option++)) ;; "ENTER"|"$current_option") show_cursor case $current_option in 1) exec "$SCRIPT_DIR/bin/clean.sh" ;; 2) exec "$SCRIPT_DIR/bin/uninstall.sh" ;; 3) clear; show_help; exit 0 ;; 4) cleanup_and_exit ;; esac ;; "QUIT") cleanup_and_exit ;; [1-4]) show_cursor case $key in 1) exec "$SCRIPT_DIR/bin/clean.sh" ;; 2) exec "$SCRIPT_DIR/bin/uninstall.sh" ;; 3) clear; show_help; exit 0 ;; 4) cleanup_and_exit ;; esac ;; esac done } main() { # Check for updates (non-blocking, won't delay startup) check_for_updates case "${1:-""}" in "clean") exec "$SCRIPT_DIR/bin/clean.sh" "${@:2}" ;; "uninstall") exec "$SCRIPT_DIR/bin/uninstall.sh" ;; "update") update_mole exit 0 ;; "help"|"--help"|"-h") show_help exit 0 ;; "version"|"--version"|"-V") show_version exit 0 ;; "") interactive_main_menu ;; *) echo "Unknown command: $1" echo "Use 'mole --help' for usage information." exit 1 ;; esac } main "$@"