mirror of
https://github.com/tw93/Mole.git
synced 2026-02-09 04:59:19 +00:00
feat: enhance system protection by adding critical path safeguards and removing problematic Spotlight and Finder/Dock cleanups.
This commit is contained in:
21
bin/clean.sh
21
bin/clean.sh
@@ -221,23 +221,10 @@ safe_clean() {
|
|||||||
for path in "${targets[@]}"; do
|
for path in "${targets[@]}"; do
|
||||||
local skip=false
|
local skip=false
|
||||||
|
|
||||||
# Hard-coded protection for critical apps (cannot be disabled by user)
|
# Centralized protection for critical apps and system components
|
||||||
case "$path" in
|
if should_protect_path "$path"; then
|
||||||
*clash* | *Clash* | *surge* | *Surge* | *mihomo* | *openvpn* | *OpenVPN* | *verge* | *Verge* | *shadowsocks* | *Shadowsocks* | *v2ray* | *V2Ray* | *sing-box* | *tailscale* | *nordvpn* | *NordVPN* | *expressvpn* | *ExpressVPN* | *protonvpn* | *ProtonVPN* | *mullvad* | *Mullvad* | *hiddify* | *Hiddify* | *loon* | *Loon* | *Cursor* | *cursor* | *Claude* | *claude* | *ChatGPT* | *chatgpt* | *Ollama* | *ollama* | *lmstudio* | *Chatbox* | *Gemini* | *gemini* | *Perplexity* | *perplexity* | *Windsurf* | *windsurf* | *Poe* | *poe* | *DiffusionBee* | *diffusionbee* | *DrawThings* | *drawthings* | *Aerial* | *aerial* | *Fliqlo* | *fliqlo* | *com.apple.finder* | *com.apple.Settings* | *com.apple.SystemSettings* | *com.apple.controlcenter*)
|
skip=true
|
||||||
skip=true
|
((skipped_count++))
|
||||||
((skipped_count++))
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Protect system app containers from accidental cleanup
|
|
||||||
# Extract bundle ID from ~/Library/Containers/<bundle_id>/... paths
|
|
||||||
if [[ "$path" == */Library/Containers/* ]] && [[ "$path" =~ /Library/Containers/([^/]+)/ ]]; then
|
|
||||||
local container_bundle_id="${BASH_REMATCH[1]}"
|
|
||||||
if should_protect_data "$container_bundle_id"; then
|
|
||||||
debug_log "Protecting system container: $container_bundle_id"
|
|
||||||
skip=true
|
|
||||||
((skipped_count++))
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ "$skip" == "true" ]] && continue
|
[[ "$skip" == "true" ]] && continue
|
||||||
|
|||||||
@@ -184,6 +184,12 @@ cleanup_path() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Centralized protection check
|
||||||
|
if should_protect_path "$expanded_path"; then
|
||||||
|
echo -e "${YELLOW}${ICON_WARNING}${NC} Protected $label"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
local size_kb
|
local size_kb
|
||||||
size_kb=$(get_path_size_kb "$expanded_path")
|
size_kb=$(get_path_size_kb "$expanded_path")
|
||||||
local size_display=""
|
local size_display=""
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ EOF
|
|||||||
items+=('log_cleanup|Diagnostics Cleanup|Purge old diagnostic & crash logs|true')
|
items+=('log_cleanup|Diagnostics Cleanup|Purge old diagnostic & crash logs|true')
|
||||||
items+=('mail_downloads|Mail Downloads|Clear old mail attachments (> 30 days)|true')
|
items+=('mail_downloads|Mail Downloads|Clear old mail attachments (> 30 days)|true')
|
||||||
items+=('swap_cleanup|Swap Refresh|Reset swap files and dynamic pager|true')
|
items+=('swap_cleanup|Swap Refresh|Reset swap files and dynamic pager|true')
|
||||||
items+=('spotlight_cache_cleanup|Spotlight Cache|Clear user-level Spotlight indexes|true')
|
|
||||||
items+=('developer_cleanup|Developer Cleanup|Clear Xcode DerivedData & DeviceSupport|true')
|
items+=('developer_cleanup|Developer Cleanup|Clear Xcode DerivedData & DeviceSupport|true')
|
||||||
items+=('network_optimization|Network Optimization|Flush DNS, ARP & reset mDNS|true')
|
items+=('network_optimization|Network Optimization|Flush DNS, ARP & reset mDNS|true')
|
||||||
|
|
||||||
|
|||||||
@@ -81,9 +81,10 @@ clean_finder_metadata() {
|
|||||||
# Clean macOS system caches
|
# Clean macOS system caches
|
||||||
clean_macos_system_caches() {
|
clean_macos_system_caches() {
|
||||||
safe_clean ~/Library/Saved\ Application\ State/* "Saved application states"
|
safe_clean ~/Library/Saved\ Application\ State/* "Saved application states"
|
||||||
safe_clean ~/Library/Caches/com.apple.spotlight "Spotlight cache"
|
|
||||||
|
|
||||||
# MOVED: Spotlight cache cleanup moved to optimize command
|
# REMOVED: Spotlight cache cleanup can cause system UI issues
|
||||||
|
# Spotlight indexes should be managed by macOS automatically
|
||||||
|
# safe_clean ~/Library/Caches/com.apple.spotlight "Spotlight cache"
|
||||||
|
|
||||||
safe_clean ~/Library/Caches/com.apple.photoanalysisd "Photo analysis cache"
|
safe_clean ~/Library/Caches/com.apple.photoanalysisd "Photo analysis cache"
|
||||||
safe_clean ~/Library/Caches/com.apple.akd "Apple ID cache"
|
safe_clean ~/Library/Caches/com.apple.akd "Apple ID cache"
|
||||||
|
|||||||
@@ -164,16 +164,19 @@ readonly DATA_PROTECTED_BUNDLES=(
|
|||||||
"com.telerik.Fiddler" # Fiddler
|
"com.telerik.Fiddler" # Fiddler
|
||||||
"com.usebruno.app" # Bruno (API client)
|
"com.usebruno.app" # Bruno (API client)
|
||||||
|
|
||||||
# Network Proxy & VPN Tools (protect all variants)
|
# ============================================================================
|
||||||
|
# Network Proxy & VPN Tools (Broad Glob Protection)
|
||||||
|
# ============================================================================
|
||||||
|
# Clash variants
|
||||||
"*clash*" # All Clash variants (ClashX, ClashX Pro, Clash Verge, etc)
|
"*clash*" # All Clash variants (ClashX, ClashX Pro, Clash Verge, etc)
|
||||||
"*Clash*" # Capitalized variants
|
"*Clash*" # Capitalized variants
|
||||||
"*clash-verge*" # Explicit Clash Verge protection
|
|
||||||
"*verge*" # Verge variants (lowercase)
|
|
||||||
"*Verge*" # Verge variants (capitalized)
|
|
||||||
"com.nssurge.surge-mac" # Surge
|
"com.nssurge.surge-mac" # Surge
|
||||||
|
"*surge*" # Surge variants
|
||||||
|
"*Surge*" # Surge variants
|
||||||
"mihomo*" # Mihomo Party and variants
|
"mihomo*" # Mihomo Party and variants
|
||||||
"*openvpn*" # OpenVPN Connect and variants
|
"*openvpn*" # OpenVPN Connect and variants
|
||||||
"*OpenVPN*" # OpenVPN capitalized variants
|
"*OpenVPN*" # OpenVPN capitalized variants
|
||||||
|
"net.openvpn.*" # OpenVPN bundle IDs
|
||||||
|
|
||||||
# Proxy Clients (Shadowsocks, V2Ray, etc)
|
# Proxy Clients (Shadowsocks, V2Ray, etc)
|
||||||
"*ShadowsocksX-NG*" # ShadowsocksX-NG
|
"*ShadowsocksX-NG*" # ShadowsocksX-NG
|
||||||
@@ -207,7 +210,12 @@ readonly DATA_PROTECTED_BUNDLES=(
|
|||||||
"*windscribe*" # Windscribe
|
"*windscribe*" # Windscribe
|
||||||
"*mullvad*" # Mullvad
|
"*mullvad*" # Mullvad
|
||||||
"*privateinternetaccess*" # PIA
|
"*privateinternetaccess*" # PIA
|
||||||
"net.openvpn.*" # OpenVPN bundle IDs
|
|
||||||
|
# Screensaver & Dynamic Wallpaper
|
||||||
|
"*Aerial*" # Aerial screensaver (all case variants)
|
||||||
|
"*aerial*" # Aerial lowercase
|
||||||
|
"*Fliqlo*" # Fliqlo screensaver (all case variants)
|
||||||
|
"*fliqlo*" # Fliqlo lowercase
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Development Tools - Git & Version Control
|
# Development Tools - Git & Version Control
|
||||||
@@ -469,6 +477,79 @@ should_protect_data() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check if a specific path should be protected from deletion
|
||||||
|
# Centralized logic to protect system settings, control center, and critical apps
|
||||||
|
#
|
||||||
|
# Args: $1 - path to check
|
||||||
|
# Returns: 0 if protected, 1 if safe to delete
|
||||||
|
should_protect_path() {
|
||||||
|
local path="$1"
|
||||||
|
[[ -z "$path" ]] && return 1
|
||||||
|
|
||||||
|
local path_lower
|
||||||
|
path_lower=$(echo "$path" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
# 1. Check for explicit critical system keywords in path (case-insensitive)
|
||||||
|
# Protect System Settings, Preferences, Control Center, and related XPC services
|
||||||
|
if [[ "$path_lower" =~ systemsettings || "$path_lower" =~ systempreferences || "$path_lower" =~ controlcenter ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Protect system-critical cache directories that cause UI corruption
|
||||||
|
# These caches are essential for modern macOS (Sonoma/Sequoia) system UI rendering
|
||||||
|
case "$path" in
|
||||||
|
# System Settings and Control Center caches (CRITICAL - prevents blank panel bug)
|
||||||
|
*com.apple.systempreferences.cache* | *com.apple.Settings.cache* | *com.apple.controlcenter.cache*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
# Finder and Dock (system essential)
|
||||||
|
*com.apple.finder.cache* | *com.apple.dock.cache*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
# System XPC services and sandboxed containers
|
||||||
|
*/Library/Containers/com.apple.Settings* | */Library/Containers/com.apple.SystemSettings* | */Library/Containers/com.apple.controlcenter*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*/Library/Group\ Containers/com.apple.systempreferences* | */Library/Group\ Containers/com.apple.Settings*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# 3. Extract bundle ID from app container/group container paths
|
||||||
|
# Matches: .../Library/Containers/bundle.id/...
|
||||||
|
# Matches: .../Library/Group Containers/group.id/...
|
||||||
|
if [[ "$path" =~ /Library/Containers/([^/]+) ]] || [[ "$path" =~ /Library/Group\ Containers/([^/]+) ]]; then
|
||||||
|
local bundle_id="${BASH_REMATCH[1]}"
|
||||||
|
if should_protect_data "$bundle_id"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Check for specific hardcoded critical patterns
|
||||||
|
case "$path" in
|
||||||
|
*com.apple.Settings* | *com.apple.SystemSettings* | *com.apple.controlcenter* | *com.apple.finder*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# 5. Check the full path against protected patterns (Broad Glob Match)
|
||||||
|
# This catches things like /Users/tw93/Library/Caches/Claude when pattern is *Claude*
|
||||||
|
for pattern in "${SYSTEM_CRITICAL_BUNDLES[@]}" "${DATA_PROTECTED_BUNDLES[@]}"; do
|
||||||
|
if bundle_matches_pattern "$path" "$pattern"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 6. Check if the filename itself matches any protected patterns
|
||||||
|
local filename
|
||||||
|
filename=$(basename "$path")
|
||||||
|
if should_protect_data "$filename"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# Find and list app-related files (consolidated from duplicates)
|
# Find and list app-related files (consolidated from duplicates)
|
||||||
find_app_files() {
|
find_app_files() {
|
||||||
local bundle_id="$1"
|
local bundle_id="$1"
|
||||||
|
|||||||
@@ -163,7 +163,6 @@ TouchID sudo check|check_touchid|config_check
|
|||||||
Rosetta 2 check|check_rosetta|config_check
|
Rosetta 2 check|check_rosetta|config_check
|
||||||
Git configuration check|check_git_config|config_check
|
Git configuration check|check_git_config|config_check
|
||||||
Login items check|check_login_items|config_check
|
Login items check|check_login_items|config_check
|
||||||
Spotlight cache cleanup|spotlight_cache|system_optimization
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,10 @@ opt_saved_state_cleanup() {
|
|||||||
# Only delete old saved states (safety window)
|
# Only delete old saved states (safety window)
|
||||||
local deleted=0
|
local deleted=0
|
||||||
while IFS= read -r -d '' state_path; do
|
while IFS= read -r -d '' state_path; do
|
||||||
|
# Protect system critical components
|
||||||
|
if should_protect_path "$state_path"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if safe_remove "$state_path" true; then
|
if safe_remove "$state_path" true; then
|
||||||
((deleted++))
|
((deleted++))
|
||||||
fi
|
fi
|
||||||
@@ -188,31 +192,6 @@ opt_saved_state_cleanup() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Finder and Dock: refresh interface caches
|
|
||||||
# REMOVED: Deleting Finder cache causes user configuration loss
|
|
||||||
# Including window positions, sidebar settings, view preferences, icon sizes
|
|
||||||
# Users reported losing Finder settings even with .DS_Store whitelist protection
|
|
||||||
# Keep this function for reference but do not use in default optimizations
|
|
||||||
opt_finder_dock_refresh() {
|
|
||||||
echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Finder & Dock caches..."
|
|
||||||
local -a interface_targets=(
|
|
||||||
"$HOME/Library/Caches/com.apple.finder|Finder cache"
|
|
||||||
"$HOME/Library/Caches/com.apple.dock.iconcache|Dock icon cache"
|
|
||||||
)
|
|
||||||
for target in "${interface_targets[@]}"; do
|
|
||||||
IFS='|' read -r target_path label <<< "$target"
|
|
||||||
cleanup_path "$target_path" "$label"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Warn user before restarting Finder (may lose unsaved work)
|
|
||||||
echo -e "${YELLOW}${ICON_WARNING}${NC} About to restart Finder & Dock (save any work in Finder windows)"
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
killall Finder > /dev/null 2>&1 || true
|
|
||||||
killall Dock > /dev/null 2>&1 || true
|
|
||||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Finder & Dock relaunched"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Swap cleanup: reset swap files
|
# Swap cleanup: reset swap files
|
||||||
opt_swap_cleanup() {
|
opt_swap_cleanup() {
|
||||||
echo -e "${BLUE}${ICON_ARROW}${NC} Removing swapfiles and resetting dynamic pager..."
|
echo -e "${BLUE}${ICON_ARROW}${NC} Removing swapfiles and resetting dynamic pager..."
|
||||||
@@ -352,54 +331,6 @@ opt_network_optimization() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Clean Spotlight user caches
|
# Clean Spotlight user caches
|
||||||
opt_spotlight_cache_cleanup() {
|
|
||||||
# Check whitelist
|
|
||||||
if is_whitelisted "spotlight_cache"; then
|
|
||||||
echo -e "${GRAY}${ICON_SUCCESS}${NC} Spotlight cache cleanup (whitelisted)"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${BLUE}${ICON_ARROW}${NC} Cleaning Spotlight user caches..."
|
|
||||||
|
|
||||||
local cleaned_count=0
|
|
||||||
local total_size_kb=0
|
|
||||||
|
|
||||||
# CoreSpotlight user cache (can grow very large)
|
|
||||||
local spotlight_cache="$HOME/Library/Metadata/CoreSpotlight"
|
|
||||||
if [[ -d "$spotlight_cache" ]]; then
|
|
||||||
local size_kb=$(get_path_size_kb "$spotlight_cache")
|
|
||||||
if [[ "$size_kb" -gt 0 ]]; then
|
|
||||||
local size_human=$(bytes_to_human "$((size_kb * 1024))")
|
|
||||||
if safe_remove "$spotlight_cache" true; then
|
|
||||||
echo -e " ${GREEN}${ICON_SUCCESS}${NC} CoreSpotlight cache ${GREEN}($size_human)${NC}"
|
|
||||||
((cleaned_count++))
|
|
||||||
((total_size_kb += size_kb))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Spotlight saved application state
|
|
||||||
local spotlight_state="$HOME/Library/Saved Application State/com.apple.spotlight.Spotlight.savedState"
|
|
||||||
if [[ -d "$spotlight_state" ]]; then
|
|
||||||
local size_kb=$(get_path_size_kb "$spotlight_state")
|
|
||||||
if [[ "$size_kb" -gt 0 ]]; then
|
|
||||||
local size_human=$(bytes_to_human "$((size_kb * 1024))")
|
|
||||||
if safe_remove "$spotlight_state" true; then
|
|
||||||
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Spotlight state ${GREEN}($size_human)${NC}"
|
|
||||||
((cleaned_count++))
|
|
||||||
((total_size_kb += size_kb))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $cleaned_count -gt 0 ]]; then
|
|
||||||
local total_human=$(bytes_to_human "$((total_size_kb * 1024))")
|
|
||||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Cleaned $cleaned_count items ${GREEN}($total_human)${NC}"
|
|
||||||
echo -e "${YELLOW}${ICON_WARNING}${NC} System settings may require logout/restart to display correctly"
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} No Spotlight caches to clean"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Execute optimization by action name
|
# Execute optimization by action name
|
||||||
execute_optimization() {
|
execute_optimization() {
|
||||||
@@ -415,13 +346,11 @@ execute_optimization() {
|
|||||||
radio_refresh) opt_radio_refresh ;;
|
radio_refresh) opt_radio_refresh ;;
|
||||||
mail_downloads) opt_mail_downloads ;;
|
mail_downloads) opt_mail_downloads ;;
|
||||||
saved_state_cleanup) opt_saved_state_cleanup ;;
|
saved_state_cleanup) opt_saved_state_cleanup ;;
|
||||||
finder_dock_refresh) opt_finder_dock_refresh ;;
|
|
||||||
swap_cleanup) opt_swap_cleanup ;;
|
swap_cleanup) opt_swap_cleanup ;;
|
||||||
startup_cache) opt_startup_cache ;;
|
startup_cache) opt_startup_cache ;;
|
||||||
local_snapshots) opt_local_snapshots ;;
|
local_snapshots) opt_local_snapshots ;;
|
||||||
developer_cleanup) opt_developer_cleanup ;;
|
developer_cleanup) opt_developer_cleanup ;;
|
||||||
fix_broken_configs) opt_fix_broken_configs ;;
|
fix_broken_configs) opt_fix_broken_configs ;;
|
||||||
spotlight_cache_cleanup) opt_spotlight_cache_cleanup ;;
|
|
||||||
network_optimization) opt_network_optimization ;;
|
network_optimization) opt_network_optimization ;;
|
||||||
*)
|
*)
|
||||||
echo -e "${RED}${ICON_ERROR}${NC} Unknown action: $action"
|
echo -e "${RED}${ICON_ERROR}${NC} Unknown action: $action"
|
||||||
|
|||||||
2
mole
2
mole
@@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
source "$SCRIPT_DIR/lib/core/common.sh"
|
source "$SCRIPT_DIR/lib/core/common.sh"
|
||||||
|
|
||||||
# Version info
|
# Version info
|
||||||
VERSION="1.13.7"
|
VERSION="1.13.8"
|
||||||
MOLE_TAGLINE="Deep clean and optimize your Mac."
|
MOLE_TAGLINE="Deep clean and optimize your Mac."
|
||||||
|
|
||||||
# Check if Touch ID is already configured
|
# Check if Touch ID is already configured
|
||||||
|
|||||||
Reference in New Issue
Block a user