mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 15:04:42 +00:00
🎨 Make the code more maintainable
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -37,4 +37,5 @@ temp/
|
||||
*.lock
|
||||
|
||||
# Claude Code
|
||||
.claude/
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
|
||||
51
README.md
51
README.md
@@ -1,23 +1,24 @@
|
||||
<div align="center">
|
||||
<img src="https://cdn.tw93.fun/pic/cole.jpg" alt="Mole Logo" width="120" height="120" style="border-radius:50%" />
|
||||
<img src="https://cdn.tw93.fun/pic/cole.png" alt="Mole Logo" width="120" height="120" style="border-radius:50%" />
|
||||
<h1 style="margin: 12px 0 6px;">Mole</h1>
|
||||
<p><em>🧹 Like a mole, dig deep to clean your mac.</em></p>
|
||||
<p><em>🦡 Dig deep like a mole to clean your Mac.</em></p>
|
||||
<p style="max-width:480px;">A Bash toolkit that tunnels through caches, leftovers, and forgotten libraries so your macOS stays fast without risking the essentials.</p>
|
||||
</div>
|
||||
|
||||
## Features
|
||||
## Highlights
|
||||
|
||||
- 🐦 Deep Clean: System/user caches, logs, temp and more
|
||||
- 🛡️ Safe by default: Skips critical system and input method settings
|
||||
- 👀 App Uninstall: Remove app bundle and related data comprehensively
|
||||
- 👻 Smooth TUI: Fast arrow-key menus with pagination for large lists
|
||||
- 🦡 Deep-clean hidden caches, logs, and temp files in one sweep
|
||||
- 🛡 Guardrails built in: skip vital macOS and input method data
|
||||
- 📦 Smart uninstall removes apps together with every leftover directory
|
||||
- ⚡️ Fast arrow-key TUI with pagination for big app lists
|
||||
|
||||
## Installation
|
||||
## Install & Update
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/tw93/mole/main/install.sh | bash
|
||||
```
|
||||
|
||||
## Usage
|
||||
## Daily Commands
|
||||
|
||||
```bash
|
||||
mole # Interactive main menu
|
||||
@@ -26,33 +27,23 @@ mole uninstall # Interactive app uninstaller
|
||||
mole --help # Show help
|
||||
```
|
||||
|
||||
### Example Output
|
||||
### Quick Peek
|
||||
|
||||
```bash
|
||||
🕳️ Mole - Deeper system cleanup
|
||||
========================
|
||||
🍎 Detected: Apple Silicon | 💾 Free space: 45.2GB
|
||||
🚀 Mode: User-level cleanup (no password required)
|
||||
$ mole clean
|
||||
🦡 MOLE — Dig deep like a mole to clean your Mac.
|
||||
|
||||
▶ System essentials
|
||||
✓ User app cache
|
||||
✓ User app logs
|
||||
✓ Trash
|
||||
Collecting inventory ...
|
||||
|
||||
▶ Browser cleanup
|
||||
✓ Safari cache
|
||||
✓ Chrome cache
|
||||
▶ System essentials freed 3.1GB (caches, logs, trash)
|
||||
▶ Browser cleanup freed 820MB (Safari, Chrome, Arc)
|
||||
▶ Developer tools freed 4.6GB (npm, Docker, Homebrew)
|
||||
|
||||
▶ Developer tools
|
||||
✓ npm cache
|
||||
✓ Docker resources
|
||||
✓ Homebrew cache
|
||||
|
||||
🎉 Cleanup complete | 💾 Freed space: 8.45GB
|
||||
📊 Items processed: 342 | 💾 Free space now: 53.7GB
|
||||
🎉 Done! 8.5GB reclaimed across 342 items.
|
||||
💡 Tip: run `mole --help` to discover more commands.
|
||||
```
|
||||
|
||||
## What Gets Cleaned
|
||||
## What Mole Cleans
|
||||
|
||||
| Category | Items Cleaned | Safety |
|
||||
|---|---|---|
|
||||
@@ -63,7 +54,7 @@ mole --help # Show help
|
||||
| 📱 Apps | Common app caches (e.g., Slack, Discord, Teams, Notion, 1Password) | Safe |
|
||||
| 🍎 Apple Silicon | Rosetta 2, media services, user activity caches | Safe |
|
||||
|
||||
## Uninstaller
|
||||
## Smart Uninstall
|
||||
|
||||
- Fast scan of `/Applications` with system-app filtering (e.g., `com.apple.*`)
|
||||
- Ranks apps by last used time and shows size hints
|
||||
|
||||
18
bin/clean.sh
18
bin/clean.sh
@@ -298,12 +298,7 @@ start_cleanup() {
|
||||
echo "🕳️ Mole - Deeper system cleanup"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
echo "This will clean:"
|
||||
echo " • App caches and logs"
|
||||
echo " • Browser data"
|
||||
echo " • Developer tool caches"
|
||||
echo " • Temporary files"
|
||||
echo " • And much more..."
|
||||
echo "This will clean: App caches & logs, Browser data, Developer tools, Temporary files & more..."
|
||||
echo ""
|
||||
|
||||
# Check if we're in an interactive terminal
|
||||
@@ -697,7 +692,7 @@ perform_cleanup() {
|
||||
end_section
|
||||
|
||||
# ===== 5. Orphaned leftovers =====
|
||||
log_header "Checking for orphaned app files"
|
||||
start_section "Orphaned app files"
|
||||
|
||||
# Build a list of installed application bundle identifiers
|
||||
echo -e " ${BLUE}🔍${NC} Building app list..."
|
||||
@@ -801,6 +796,7 @@ perform_cleanup() {
|
||||
if [ "$found_orphaned" = false ]; then
|
||||
echo -e " ${GREEN}✓${NC} No orphaned files found"
|
||||
fi
|
||||
end_section
|
||||
|
||||
# Common temp and test data
|
||||
safe_clean ~/Library/Application\ Support/TestApp* "Test app data"
|
||||
@@ -823,12 +819,13 @@ perform_cleanup() {
|
||||
# System cleanup was moved to the beginning (right after password verification)
|
||||
|
||||
# ===== 7. iOS device backups =====
|
||||
log_header "Checking iOS device backups..."
|
||||
start_section "iOS device backups"
|
||||
backup_dir="$HOME/Library/Application Support/MobileSync/Backup"
|
||||
if [[ -d "$backup_dir" ]] && find "$backup_dir" -mindepth 1 -maxdepth 1 | read -r _; then
|
||||
backup_kb=$(du -sk "$backup_dir" 2>/dev/null | awk '{print $1}')
|
||||
if [[ -n "${backup_kb:-}" && "$backup_kb" -gt 102400 ]]; then # >100MB
|
||||
backup_human=$(du -shm "$backup_dir" 2>/dev/null | awk '{print $1"M"}')
|
||||
note_activity
|
||||
echo -e " 👉 Found ${GREEN}${backup_human}${NC}, you can delete it manually"
|
||||
echo -e " 👉 ${backup_dir}"
|
||||
else
|
||||
@@ -837,9 +834,11 @@ perform_cleanup() {
|
||||
else
|
||||
echo -e " ${BLUE}✨${NC} Nothing to tidy"
|
||||
fi
|
||||
end_section
|
||||
|
||||
# ===== 8. Summary =====
|
||||
log_header "Cleanup summary"
|
||||
start_section "Cleanup summary"
|
||||
note_activity
|
||||
space_after=$(df / | tail -1 | awk '{print $4}')
|
||||
current_space_after=$(get_free_space)
|
||||
|
||||
@@ -864,6 +863,7 @@ perform_cleanup() {
|
||||
fi
|
||||
|
||||
echo "==================================================================="
|
||||
end_section
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
292
lib/common.sh
Normal file → Executable file
292
lib/common.sh
Normal file → Executable file
@@ -2,20 +2,63 @@
|
||||
# Mole - Common Functions Library
|
||||
# Shared utilities and functions for all modules
|
||||
|
||||
# Color definitions
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
PURPLE='\033[0;35m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
set -euo pipefail
|
||||
|
||||
# Logging functions
|
||||
log_info() { echo -e "${BLUE}$1${NC}"; }
|
||||
log_success() { echo -e "${GREEN}✅ $1${NC}"; }
|
||||
log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
|
||||
log_error() { echo -e "${RED}❌ $1${NC}"; }
|
||||
log_header() { echo -e "\n${PURPLE}▶ $1${NC}"; }
|
||||
# Color definitions (readonly for safety)
|
||||
readonly ESC=$'\033'
|
||||
readonly GREEN="${ESC}[0;32m"
|
||||
readonly BLUE="${ESC}[0;34m"
|
||||
readonly YELLOW="${ESC}[1;33m"
|
||||
readonly PURPLE="${ESC}[0;35m"
|
||||
readonly RED="${ESC}[0;31m"
|
||||
readonly NC="${ESC}[0m"
|
||||
|
||||
# Logging configuration
|
||||
readonly LOG_FILE="${HOME}/.config/mole/mole.log"
|
||||
readonly LOG_MAX_SIZE_DEFAULT=1048576 # 1MB
|
||||
|
||||
# Ensure log directory exists
|
||||
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
|
||||
|
||||
# Enhanced logging functions with file logging support
|
||||
log_info() {
|
||||
rotate_log
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_success() {
|
||||
rotate_log
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS: $1" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
rotate_log
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: $1" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_error() {
|
||||
rotate_log
|
||||
echo -e "${RED}❌ $1${NC}" >&2
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_header() {
|
||||
rotate_log
|
||||
echo -e "\n${PURPLE}▶ $1${NC}"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SECTION: $1" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Log file maintenance
|
||||
rotate_log() {
|
||||
local max_size="${MOLE_MAX_LOG_SIZE:-$LOG_MAX_SIZE_DEFAULT}"
|
||||
if [[ -f "$LOG_FILE" ]] && [[ $(stat -f%z "$LOG_FILE" 2>/dev/null || echo 0) -gt "$max_size" ]]; then
|
||||
mv "$LOG_FILE" "${LOG_FILE}.old" 2>/dev/null || true
|
||||
touch "$LOG_FILE" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# System detection
|
||||
detect_architecture() {
|
||||
@@ -96,9 +139,69 @@ handle_error() {
|
||||
# File size utilities
|
||||
get_human_size() {
|
||||
local path="$1"
|
||||
if [[ ! -e "$path" ]]; then
|
||||
echo "N/A"
|
||||
return 1
|
||||
fi
|
||||
du -sh "$path" 2>/dev/null | cut -f1 || echo "N/A"
|
||||
}
|
||||
|
||||
# Convert bytes to human readable format
|
||||
bytes_to_human() {
|
||||
local bytes="$1"
|
||||
if [[ ! "$bytes" =~ ^[0-9]+$ ]]; then
|
||||
echo "0B"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ((bytes >= 1073741824)); then # >= 1GB
|
||||
echo "$bytes" | awk '{printf "%.2fGB", $1/1073741824}'
|
||||
elif ((bytes >= 1048576)); then # >= 1MB
|
||||
echo "$bytes" | awk '{printf "%.1fMB", $1/1048576}'
|
||||
elif ((bytes >= 1024)); then # >= 1KB
|
||||
echo "$bytes" | awk '{printf "%.0fKB", $1/1024}'
|
||||
else
|
||||
echo "${bytes}B"
|
||||
fi
|
||||
}
|
||||
|
||||
# Calculate directory size in bytes
|
||||
get_directory_size_bytes() {
|
||||
local path="$1"
|
||||
if [[ ! -d "$path" ]]; then
|
||||
echo "0"
|
||||
return 1
|
||||
fi
|
||||
du -sk "$path" 2>/dev/null | cut -f1 | awk '{print $1 * 1024}' || echo "0"
|
||||
}
|
||||
|
||||
# Safe file operation with backup
|
||||
safe_remove() {
|
||||
local path="$1"
|
||||
local backup_dir="${2:-/tmp/mole_backup_$(date +%s)}"
|
||||
local backup_enabled="${MOLE_BACKUP_ENABLED:-true}"
|
||||
|
||||
if [[ ! -e "$path" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$backup_enabled" == "true" ]]; then
|
||||
# Create backup directory if it doesn't exist
|
||||
mkdir -p "$backup_dir" 2>/dev/null || return 1
|
||||
|
||||
local basename_path
|
||||
basename_path=$(basename "$path")
|
||||
|
||||
if ! cp -R "$path" "$backup_dir/$basename_path" 2>/dev/null; then
|
||||
log_warning "Backup failed for $path, skipping removal"
|
||||
return 1
|
||||
fi
|
||||
log_info "Backup created at $backup_dir/$basename_path"
|
||||
fi
|
||||
|
||||
rm -rf "$path" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Permission checks
|
||||
check_sudo() {
|
||||
if ! sudo -n true 2>/dev/null; then
|
||||
@@ -119,3 +222,166 @@ request_sudo() {
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configuration management
|
||||
readonly CONFIG_FILE="${HOME}/.config/mole/config"
|
||||
|
||||
# Load configuration with defaults
|
||||
load_config() {
|
||||
# Default configuration
|
||||
MOLE_LOG_LEVEL="${MOLE_LOG_LEVEL:-INFO}"
|
||||
MOLE_AUTO_CONFIRM="${MOLE_AUTO_CONFIRM:-false}"
|
||||
MOLE_BACKUP_ENABLED="${MOLE_BACKUP_ENABLED:-true}"
|
||||
MOLE_MAX_LOG_SIZE="${MOLE_MAX_LOG_SIZE:-1048576}"
|
||||
MOLE_PARALLEL_JOBS="${MOLE_PARALLEL_JOBS:-}" # Empty means auto-detect
|
||||
|
||||
# Load user configuration if exists
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
source "$CONFIG_FILE" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Save configuration
|
||||
save_config() {
|
||||
mkdir -p "$(dirname "$CONFIG_FILE")" 2>/dev/null || return 1
|
||||
cat > "$CONFIG_FILE" << EOF
|
||||
# Mole Configuration File
|
||||
# Generated on $(date)
|
||||
|
||||
# Log level: DEBUG, INFO, WARNING, ERROR
|
||||
MOLE_LOG_LEVEL="$MOLE_LOG_LEVEL"
|
||||
|
||||
# Auto confirm operations (true/false)
|
||||
MOLE_AUTO_CONFIRM="$MOLE_AUTO_CONFIRM"
|
||||
|
||||
# Enable backup before deletion (true/false)
|
||||
MOLE_BACKUP_ENABLED="$MOLE_BACKUP_ENABLED"
|
||||
|
||||
# Maximum log file size in bytes
|
||||
MOLE_MAX_LOG_SIZE="$MOLE_MAX_LOG_SIZE"
|
||||
|
||||
# Number of parallel jobs for operations (empty = auto-detect)
|
||||
MOLE_PARALLEL_JOBS="$MOLE_PARALLEL_JOBS"
|
||||
EOF
|
||||
}
|
||||
|
||||
# Progress tracking
|
||||
# Use parameter expansion for portable global initialization (macOS bash lacks declare -g).
|
||||
: "${PROGRESS_CURRENT:=0}"
|
||||
: "${PROGRESS_TOTAL:=0}"
|
||||
: "${PROGRESS_MESSAGE:=}"
|
||||
|
||||
# Initialize progress tracking
|
||||
init_progress() {
|
||||
PROGRESS_CURRENT=0
|
||||
PROGRESS_TOTAL="$1"
|
||||
PROGRESS_MESSAGE="${2:-Processing}"
|
||||
}
|
||||
|
||||
# Update progress
|
||||
update_progress() {
|
||||
PROGRESS_CURRENT="$1"
|
||||
local message="${2:-$PROGRESS_MESSAGE}"
|
||||
local percentage=$((PROGRESS_CURRENT * 100 / PROGRESS_TOTAL))
|
||||
|
||||
# Create progress bar
|
||||
local bar_length=20
|
||||
local filled_length=$((percentage * bar_length / 100))
|
||||
local bar=""
|
||||
|
||||
for ((i=0; i<filled_length; i++)); do
|
||||
bar="${bar}█"
|
||||
done
|
||||
|
||||
for ((i=filled_length; i<bar_length; i++)); do
|
||||
bar="${bar}░"
|
||||
done
|
||||
|
||||
printf "\r${BLUE}[%s] %3d%% %s (%d/%d)${NC}" "$bar" "$percentage" "$message" "$PROGRESS_CURRENT" "$PROGRESS_TOTAL"
|
||||
|
||||
if [[ $PROGRESS_CURRENT -eq $PROGRESS_TOTAL ]]; then
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
# Spinner for indeterminate progress
|
||||
: "${SPINNER_PID:=}"
|
||||
|
||||
start_spinner() {
|
||||
local message="${1:-Working}"
|
||||
stop_spinner # Stop any existing spinner
|
||||
|
||||
(
|
||||
local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
||||
local i=0
|
||||
while true; do
|
||||
printf "\r${BLUE}%s %s${NC}" "${spin:$i:1}" "$message"
|
||||
((i++))
|
||||
if [[ $i -eq ${#spin} ]]; then
|
||||
i=0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
) &
|
||||
SPINNER_PID=$!
|
||||
}
|
||||
|
||||
stop_spinner() {
|
||||
if [[ -n "$SPINNER_PID" ]]; then
|
||||
kill "$SPINNER_PID" 2>/dev/null || true
|
||||
wait "$SPINNER_PID" 2>/dev/null || true
|
||||
SPINNER_PID=""
|
||||
printf "\r\033[K" # Clear the line
|
||||
fi
|
||||
}
|
||||
|
||||
# Calculate optimal parallel jobs based on system resources
|
||||
get_optimal_parallel_jobs() {
|
||||
local operation_type="${1:-default}"
|
||||
local optimal_parallel=4
|
||||
|
||||
# Try to detect optimal parallel jobs based on CPU cores
|
||||
if command -v nproc >/dev/null 2>&1; then
|
||||
optimal_parallel=$(nproc)
|
||||
elif command -v sysctl >/dev/null 2>&1; then
|
||||
optimal_parallel=$(sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
||||
fi
|
||||
|
||||
# Apply operation-specific limits
|
||||
case "$operation_type" in
|
||||
"scan")
|
||||
# For scanning: min 2, max 8
|
||||
if [[ $optimal_parallel -lt 2 ]]; then
|
||||
optimal_parallel=2
|
||||
elif [[ $optimal_parallel -gt 8 ]]; then
|
||||
optimal_parallel=8
|
||||
fi
|
||||
;;
|
||||
"clean")
|
||||
# For file operations: min 2, max 6 (more conservative)
|
||||
if [[ $optimal_parallel -lt 2 ]]; then
|
||||
optimal_parallel=2
|
||||
elif [[ $optimal_parallel -gt 6 ]]; then
|
||||
optimal_parallel=6
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Default: min 2, max 4 (safest)
|
||||
if [[ $optimal_parallel -lt 2 ]]; then
|
||||
optimal_parallel=2
|
||||
elif [[ $optimal_parallel -gt 4 ]]; then
|
||||
optimal_parallel=4
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Use configured value if available, otherwise use calculated optimal
|
||||
if [[ -n "${MOLE_PARALLEL_JOBS:-}" ]]; then
|
||||
echo "$MOLE_PARALLEL_JOBS"
|
||||
else
|
||||
echo "$optimal_parallel"
|
||||
fi
|
||||
}
|
||||
|
||||
# Initialize configuration on sourcing
|
||||
load_config
|
||||
|
||||
@@ -7,8 +7,10 @@ declare -a menu_options=()
|
||||
declare -i selected=0
|
||||
declare -i menu_size=0
|
||||
|
||||
# ANSI escape sequences
|
||||
readonly ESC=$'\033'
|
||||
# ANSI escape sequences (allow reuse when sourced after lib/common.sh)
|
||||
if [[ -z "${ESC+x}" ]]; then
|
||||
readonly ESC=$'\033'
|
||||
fi
|
||||
readonly UP="${ESC}[A"
|
||||
readonly DOWN="${ESC}[B"
|
||||
readonly ENTER=$'\n'
|
||||
|
||||
32
mole
32
mole
@@ -21,23 +21,27 @@ source "$SCRIPT_DIR/lib/common.sh"
|
||||
|
||||
# Version info
|
||||
VERSION="1.0.0"
|
||||
MOLE_TAGLINE="Dig deep like a mole to clean your Mac."
|
||||
|
||||
show_brand_banner() {
|
||||
printf '%b🦡 %bMOLE%b — %b%s%b\n' \
|
||||
"$PURPLE" "$BLUE" "$NC" "$GREEN" "$MOLE_TAGLINE" "$NC"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat <<'EOF'
|
||||
Mole can dig deep to clean your mac.
|
||||
=====================================
|
||||
show_brand_banner
|
||||
echo
|
||||
printf "%s%s%s\n" "$BLUE" "USAGE" "$NC"
|
||||
printf " %s%s%s [command]\n\n" "$GREEN" "mole" "$NC"
|
||||
|
||||
USAGE:
|
||||
mole [command]
|
||||
printf "%s%s%s\n" "$BLUE" "COMMANDS" "$NC"
|
||||
printf " %s%-16s%s %s\n" "$GREEN" "mole" "$NC" "Interactive main menu"
|
||||
printf " %s%-16s%s %s\n" "$GREEN" "mole clean" "$NC" "Deeper system cleanup"
|
||||
printf " %s%-16s%s %s\n" "$GREEN" "mole uninstall" "$NC" "Remove applications completely"
|
||||
printf " %s%-16s%s %s\n" "$GREEN" "mole --help" "$NC" "Show this help message"
|
||||
|
||||
COMMANDS:
|
||||
mole # Interactive main menu
|
||||
mole clean # Deeper system cleanup
|
||||
mole uninstall # Remove applications completely
|
||||
mole --help # Show this help message
|
||||
|
||||
For more information, visit: https://github.com/tw93/mole
|
||||
EOF
|
||||
printf "\n%s%s%s\n" "$BLUE" "MORE" "$NC"
|
||||
printf " https://github.com/tw93/mole\n"
|
||||
}
|
||||
|
||||
show_main_menu() {
|
||||
@@ -46,7 +50,7 @@ show_main_menu() {
|
||||
|
||||
if [[ "$redraw_full" == "true" ]]; then
|
||||
echo ""
|
||||
echo "Mole can dig deep to clean your mac."
|
||||
show_brand_banner
|
||||
echo ""
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user