From df7e5c8a04fedf247fc5d2d3c637d7f77dc5abf9 Mon Sep 17 00:00:00 2001 From: Tw93 Date: Thu, 18 Dec 2025 10:42:13 +0800 Subject: [PATCH] feat: enhance system protection by adding critical path safeguards and removing problematic Spotlight and Finder/Dock cleanups. --- bin/clean.sh | 21 ++------- bin/optimize.sh | 6 +++ lib/check/health_json.sh | 1 - lib/clean/user.sh | 5 ++- lib/core/app_protection.sh | 91 +++++++++++++++++++++++++++++++++++--- lib/manage/whitelist.sh | 1 - lib/optimize/tasks.sh | 79 ++------------------------------- mole | 2 +- 8 files changed, 104 insertions(+), 102 deletions(-) diff --git a/bin/clean.sh b/bin/clean.sh index b349834..5d7d4a3 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -221,23 +221,10 @@ safe_clean() { for path in "${targets[@]}"; do local skip=false - # Hard-coded protection for critical apps (cannot be disabled by user) - case "$path" in - *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 - ((skipped_count++)) - ;; - esac - - # Protect system app containers from accidental cleanup - # Extract bundle ID from ~/Library/Containers//... 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 + # Centralized protection for critical apps and system components + if should_protect_path "$path"; then + skip=true + ((skipped_count++)) fi [[ "$skip" == "true" ]] && continue diff --git a/bin/optimize.sh b/bin/optimize.sh index 8215962..0c43a42 100755 --- a/bin/optimize.sh +++ b/bin/optimize.sh @@ -184,6 +184,12 @@ cleanup_path() { return fi + # Centralized protection check + if should_protect_path "$expanded_path"; then + echo -e "${YELLOW}${ICON_WARNING}${NC} Protected $label" + return + fi + local size_kb size_kb=$(get_path_size_kb "$expanded_path") local size_display="" diff --git a/lib/check/health_json.sh b/lib/check/health_json.sh index dec4731..f3e314c 100644 --- a/lib/check/health_json.sh +++ b/lib/check/health_json.sh @@ -129,7 +129,6 @@ EOF items+=('log_cleanup|Diagnostics Cleanup|Purge old diagnostic & crash logs|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+=('spotlight_cache_cleanup|Spotlight Cache|Clear user-level Spotlight indexes|true') items+=('developer_cleanup|Developer Cleanup|Clear Xcode DerivedData & DeviceSupport|true') items+=('network_optimization|Network Optimization|Flush DNS, ARP & reset mDNS|true') diff --git a/lib/clean/user.sh b/lib/clean/user.sh index 4f61659..d1a7c23 100644 --- a/lib/clean/user.sh +++ b/lib/clean/user.sh @@ -81,9 +81,10 @@ clean_finder_metadata() { # Clean macOS system caches clean_macos_system_caches() { 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.akd "Apple ID cache" diff --git a/lib/core/app_protection.sh b/lib/core/app_protection.sh index 466966d..eb62a75 100755 --- a/lib/core/app_protection.sh +++ b/lib/core/app_protection.sh @@ -164,16 +164,19 @@ readonly DATA_PROTECTED_BUNDLES=( "com.telerik.Fiddler" # Fiddler "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*" # Capitalized variants - "*clash-verge*" # Explicit Clash Verge protection - "*verge*" # Verge variants (lowercase) - "*Verge*" # Verge variants (capitalized) "com.nssurge.surge-mac" # Surge + "*surge*" # Surge variants + "*Surge*" # Surge variants "mihomo*" # Mihomo Party and variants "*openvpn*" # OpenVPN Connect and variants "*OpenVPN*" # OpenVPN capitalized variants + "net.openvpn.*" # OpenVPN bundle IDs # Proxy Clients (Shadowsocks, V2Ray, etc) "*ShadowsocksX-NG*" # ShadowsocksX-NG @@ -207,7 +210,12 @@ readonly DATA_PROTECTED_BUNDLES=( "*windscribe*" # Windscribe "*mullvad*" # Mullvad "*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 @@ -469,6 +477,79 @@ should_protect_data() { 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_app_files() { local bundle_id="$1" diff --git a/lib/manage/whitelist.sh b/lib/manage/whitelist.sh index 3e9861d..fd8a432 100755 --- a/lib/manage/whitelist.sh +++ b/lib/manage/whitelist.sh @@ -163,7 +163,6 @@ TouchID sudo check|check_touchid|config_check Rosetta 2 check|check_rosetta|config_check Git configuration check|check_git_config|config_check Login items check|check_login_items|config_check -Spotlight cache cleanup|spotlight_cache|system_optimization EOF } diff --git a/lib/optimize/tasks.sh b/lib/optimize/tasks.sh index 35c5792..9a30fd9 100644 --- a/lib/optimize/tasks.sh +++ b/lib/optimize/tasks.sh @@ -176,6 +176,10 @@ opt_saved_state_cleanup() { # Only delete old saved states (safety window) local deleted=0 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 ((deleted++)) fi @@ -188,31 +192,6 @@ opt_saved_state_cleanup() { 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 opt_swap_cleanup() { echo -e "${BLUE}${ICON_ARROW}${NC} Removing swapfiles and resetting dynamic pager..." @@ -352,54 +331,6 @@ opt_network_optimization() { } # 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() { @@ -415,13 +346,11 @@ execute_optimization() { radio_refresh) opt_radio_refresh ;; mail_downloads) opt_mail_downloads ;; saved_state_cleanup) opt_saved_state_cleanup ;; - finder_dock_refresh) opt_finder_dock_refresh ;; swap_cleanup) opt_swap_cleanup ;; startup_cache) opt_startup_cache ;; local_snapshots) opt_local_snapshots ;; developer_cleanup) opt_developer_cleanup ;; fix_broken_configs) opt_fix_broken_configs ;; - spotlight_cache_cleanup) opt_spotlight_cache_cleanup ;; network_optimization) opt_network_optimization ;; *) echo -e "${RED}${ICON_ERROR}${NC} Unknown action: $action" diff --git a/mole b/mole index eec69eb..4f1fbbb 100755 --- a/mole +++ b/mole @@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/lib/core/common.sh" # Version info -VERSION="1.13.7" +VERSION="1.13.8" MOLE_TAGLINE="Deep clean and optimize your Mac." # Check if Touch ID is already configured