diff --git a/bin/clean.sh b/bin/clean.sh index 98559e7..592e3df 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -19,7 +19,6 @@ source "$SCRIPT_DIR/../lib/clean/dev.sh" source "$SCRIPT_DIR/../lib/clean/app_caches.sh" source "$SCRIPT_DIR/../lib/clean/system.sh" source "$SCRIPT_DIR/../lib/clean/user.sh" -source "$SCRIPT_DIR/../lib/clean/maintenance.sh" # Configuration SYSTEM_CLEAN=false @@ -869,11 +868,6 @@ perform_cleanup() { clean_time_machine_failed_backups end_section - # ===== 16. System maintenance ===== - start_section "System maintenance" - # Broken preferences and login items cleanup (delegated to clean_maintenance module) - clean_maintenance - end_section # ===== Final summary ===== echo "" diff --git a/bin/optimize.sh b/bin/optimize.sh index b91292b..fc231bf 100755 --- a/bin/optimize.sh +++ b/bin/optimize.sh @@ -8,6 +8,7 @@ source "$SCRIPT_DIR/lib/core/common.sh" source "$SCRIPT_DIR/lib/core/sudo.sh" source "$SCRIPT_DIR/lib/manage/update.sh" source "$SCRIPT_DIR/lib/manage/autofix.sh" +source "$SCRIPT_DIR/lib/optimize/maintenance.sh" source "$SCRIPT_DIR/lib/optimize/tasks.sh" # Load check modules diff --git a/lib/clean/maintenance.sh b/lib/optimize/maintenance.sh similarity index 59% rename from lib/clean/maintenance.sh rename to lib/optimize/maintenance.sh index 2c27acc..c715b94 100644 --- a/lib/clean/maintenance.sh +++ b/lib/optimize/maintenance.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Maintenance Cleanup Module -# Broken preferences and broken login items cleanup +# System Configuration Maintenance Module +# Fix broken preferences and broken login items set -euo pipefail @@ -11,18 +11,12 @@ set -euo pipefail # Clean broken preference files # Uses plutil -lint to validate plist files -# Env: DRY_RUN -# Globals: files_cleaned, total_size_cleaned, total_items (modified) -clean_broken_preferences() { +# Returns: count of broken files fixed +fix_broken_preferences() { local prefs_dir="$HOME/Library/Preferences" [[ -d "$prefs_dir" ]] || return 0 local broken_count=0 - local total_size_kb=0 - - if [[ -t 1 ]]; then - MOLE_SPINNER_PREFIX=" " start_inline_spinner "Checking preference files..." - fi # Check main preferences directory while IFS= read -r plist_file; do @@ -40,13 +34,9 @@ clean_broken_preferences() { # Validate plist using plutil plutil -lint "$plist_file" > /dev/null 2>&1 && continue - local size_kb - size_kb=$(get_path_size_kb "$plist_file") - - [[ "$DRY_RUN" != "true" ]] && rm -f "$plist_file" 2> /dev/null || true - + # Remove broken plist + rm -f "$plist_file" 2> /dev/null || true ((broken_count++)) - ((total_size_kb += size_kb)) done < <(run_with_timeout 10 sh -c "find '$prefs_dir' -maxdepth 1 -name '*.plist' -type f 2> /dev/null || true") # Check ByHost preferences with timeout protection @@ -65,32 +55,12 @@ clean_broken_preferences() { plutil -lint "$plist_file" > /dev/null 2>&1 && continue - local size_kb - size_kb=$(run_with_timeout 5 get_path_size_kb "$plist_file") - - [[ "$DRY_RUN" != "true" ]] && rm -f "$plist_file" 2> /dev/null || true - + rm -f "$plist_file" 2> /dev/null || true ((broken_count++)) - ((total_size_kb += size_kb)) done < <(run_with_timeout 10 sh -c "find '$byhost_dir' -name '*.plist' -type f 2> /dev/null || true") fi - if [[ -t 1 ]]; then - stop_inline_spinner - fi - - if [[ $broken_count -gt 0 ]]; then - if [[ "$DRY_RUN" == "true" ]]; then - echo -e " ${YELLOW}→${NC} Broken preferences: $broken_count files ${YELLOW}(dry)${NC}" - else - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Removed $broken_count broken preference files" - fi - # Update global statistics - ((files_cleaned += broken_count)) - ((total_size_cleaned += total_size_kb)) - ((total_items++)) - note_activity - fi + echo "$broken_count" } # ============================================================================ @@ -99,18 +69,12 @@ clean_broken_preferences() { # ============================================================================ # Clean broken login items (LaunchAgents pointing to missing executables) -# Env: DRY_RUN -# Globals: files_cleaned, total_items (modified) -clean_broken_login_items() { +# Returns: count of broken items fixed +fix_broken_login_items() { local launch_agents_dir="$HOME/Library/LaunchAgents" [[ -d "$launch_agents_dir" ]] || return 0 local broken_count=0 - local total_size_kb=0 - - if [[ -t 1 ]]; then - MOLE_SPINNER_PREFIX=" " start_inline_spinner "Checking login items..." - fi while IFS= read -r plist_file; do [[ -f "$plist_file" ]] || continue @@ -138,41 +102,54 @@ clean_broken_login_items() { [[ -e "$program" ]] && continue # Program doesn't exist - this is a broken login item - local size_kb - size_kb=$(get_path_size_kb "$plist_file") - - if [[ "$DRY_RUN" != "true" ]]; then - launchctl unload "$plist_file" 2> /dev/null || true - rm -f "$plist_file" 2> /dev/null || true - fi - + launchctl unload "$plist_file" 2> /dev/null || true + rm -f "$plist_file" 2> /dev/null || true ((broken_count++)) - ((total_size_kb += size_kb)) done < <(run_with_timeout 10 sh -c "find '$launch_agents_dir' -name '*.plist' -type f 2> /dev/null || true") - if [[ -t 1 ]]; then - stop_inline_spinner - fi - - if [[ $broken_count -gt 0 ]]; then - if [[ "$DRY_RUN" == "true" ]]; then - echo -e " ${YELLOW}→${NC} Broken login items: $broken_count ${YELLOW}(dry)${NC}" - else - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Removed $broken_count broken login items" - fi - # Update global statistics - ((files_cleaned += broken_count)) - ((total_size_cleaned += total_size_kb)) - ((total_items++)) - note_activity - fi + echo "$broken_count" } # ============================================================================ -# Main maintenance cleanup function +# Check for broken configurations +# Returns: JSON line if issues found, empty otherwise # ============================================================================ -clean_maintenance() { - clean_broken_preferences - clean_broken_login_items +check_broken_configs() { + local prefs_dir="$HOME/Library/Preferences" + local launch_agents_dir="$HOME/Library/LaunchAgents" + + local broken_prefs=0 + local broken_items=0 + + # Count broken preferences + if [[ -d "$prefs_dir" ]]; then + while IFS= read -r plist_file; do + [[ -f "$plist_file" ]] || continue + local filename=$(basename "$plist_file") + case "$filename" in + com.apple.* | .GlobalPreferences* | loginwindow.plist) continue ;; + esac + plutil -lint "$plist_file" > /dev/null 2>&1 || ((broken_prefs++)) + done < <(run_with_timeout 10 sh -c "find '$prefs_dir' -maxdepth 1 -name '*.plist' -type f 2> /dev/null || true") + fi + + # Count broken login items + if [[ -d "$launch_agents_dir" ]]; then + while IFS= read -r plist_file; do + [[ -f "$plist_file" ]] || continue + local filename=$(basename "$plist_file") + case "$filename" in com.apple.*) continue ;; esac + + local program=$(plutil -extract Program raw "$plist_file" 2> /dev/null || echo "") + [[ -z "$program" ]] && program=$(plutil -extract ProgramArguments.0 raw "$plist_file" 2> /dev/null || echo "") + [[ -z "$program" ]] && continue + [[ -e "$program" ]] || ((broken_items++)) + done < <(run_with_timeout 10 sh -c "find '$launch_agents_dir' -name '*.plist' -type f 2> /dev/null || true") + fi + + local total=$((broken_prefs + broken_items)) + if [[ $total -gt 0 ]]; then + echo "fix_broken_configs|Fix Broken Configurations|Fix $total broken preference/login item files|false" + fi } diff --git a/lib/optimize/tasks.sh b/lib/optimize/tasks.sh index 98348e8..7b3e167 100644 --- a/lib/optimize/tasks.sh +++ b/lib/optimize/tasks.sh @@ -385,6 +385,36 @@ opt_developer_cleanup() { echo -e "${GREEN}${ICON_SUCCESS}${NC} Developer caches cleaned" } +# Fix broken system configurations +# Repairs corrupted preference files and broken login items +opt_fix_broken_configs() { + local broken_prefs=0 + local broken_items=0 + + # Fix broken preferences + echo -e "${BLUE}${ICON_ARROW}${NC} Checking preference files..." + broken_prefs=$(fix_broken_preferences) + if [[ $broken_prefs -gt 0 ]]; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Fixed $broken_prefs broken preference files" + else + echo -e "${GREEN}${ICON_SUCCESS}${NC} All preference files valid" + fi + + # Fix broken login items + echo -e "${BLUE}${ICON_ARROW}${NC} Checking login items..." + broken_items=$(fix_broken_login_items) + if [[ $broken_items -gt 0 ]]; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Removed $broken_items broken login items" + else + echo -e "${GREEN}${ICON_SUCCESS}${NC} All login items valid" + fi + + local total=$((broken_prefs + broken_items)) + if [[ $total -gt 0 ]]; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} System configuration repaired" + fi +} + # Execute optimization by action name execute_optimization() { local action="$1" @@ -404,6 +434,7 @@ execute_optimization() { startup_cache) opt_startup_cache ;; local_snapshots) opt_local_snapshots ;; developer_cleanup) opt_developer_cleanup ;; + fix_broken_configs) opt_fix_broken_configs ;; *) echo -e "${RED}${ICON_ERROR}${NC} Unknown action: $action" return 1 @@ -653,6 +684,8 @@ EOF [[ -n "$item" ]] && items+=("$item") item=$(check_developer_cleanup || true) [[ -n "$item" ]] && items+=("$item") + item=$(check_broken_configs || true) + [[ -n "$item" ]] && items+=("$item") # Output items as JSON local first=true