From cccc41990e0752103c00d4f01585d9a54f7fe6fd Mon Sep 17 00:00:00 2001 From: Tw93 Date: Sat, 15 Nov 2025 13:20:58 +0800 Subject: [PATCH] Apply scan cache to simplify --- bin/optimize.sh | 954 ++++++++++++++++++++--------------------- bin/uninstall.sh | 61 +-- lib/optimize_health.sh | 43 +- scripts/check.sh | 8 +- 4 files changed, 520 insertions(+), 546 deletions(-) diff --git a/bin/optimize.sh b/bin/optimize.sh index 8ab1298..7fedd22 100755 --- a/bin/optimize.sh +++ b/bin/optimize.sh @@ -10,598 +10,598 @@ source "$SCRIPT_DIR/lib/optimize_health.sh" # Colors and icons from common.sh print_header() { - echo "" - echo -e "${PURPLE}Optimize Your Mac${NC}" - echo "" + echo "" + echo -e "${PURPLE}Optimize Your Mac${NC}" + echo "" } show_system_health() { - local health_json="$1" + local health_json="$1" - # Parse system health using jq - local mem_used=$(echo "$health_json" | jq -r '.memory_used_gb') - local mem_total=$(echo "$health_json" | jq -r '.memory_total_gb') - local disk_used=$(echo "$health_json" | jq -r '.disk_used_gb') - local disk_total=$(echo "$health_json" | jq -r '.disk_total_gb') - local disk_percent=$(echo "$health_json" | jq -r '.disk_used_percent') - local uptime=$(echo "$health_json" | jq -r '.uptime_days') + # Parse system health using jq + local mem_used=$(echo "$health_json" | jq -r '.memory_used_gb') + local mem_total=$(echo "$health_json" | jq -r '.memory_total_gb') + local disk_used=$(echo "$health_json" | jq -r '.disk_used_gb') + local disk_total=$(echo "$health_json" | jq -r '.disk_total_gb') + local disk_percent=$(echo "$health_json" | jq -r '.disk_used_percent') + local uptime=$(echo "$health_json" | jq -r '.uptime_days') - # Compact one-line format - printf "System: %.0f/%.0f GB RAM | %.0f/%.0f GB Disk (%.0f%%) | Uptime %.0fd\n" \ - "$mem_used" "$mem_total" "$disk_used" "$disk_total" "$disk_percent" "$uptime" - echo "" + # Compact one-line format + printf "System: %.0f/%.0f GB RAM | %.0f/%.0f GB Disk (%.0f%%) | Uptime %.0fd\n" \ + "$mem_used" "$mem_total" "$disk_used" "$disk_total" "$disk_percent" "$uptime" + echo "" } parse_optimizations() { - local health_json="$1" + local health_json="$1" - # Extract optimizations array - echo "$health_json" | jq -c '.optimizations[]' 2> /dev/null + # Extract optimizations array + echo "$health_json" | jq -c '.optimizations[]' 2> /dev/null } announce_action() { - local name="$1" - local desc="$2" - local kind="$3" + local name="$1" + local desc="$2" + local kind="$3" - local badge="" - if [[ "$kind" == "confirm" ]]; then - badge="${YELLOW}[Confirm]${NC} " - fi + local badge="" + if [[ "$kind" == "confirm" ]]; then + badge="${YELLOW}[Confirm]${NC} " + fi - local line="${BLUE}${ICON_ARROW}${NC} ${badge}${name}" - if [[ -n "$desc" ]]; then - line+=" ${GRAY}- ${desc}${NC}" - fi + local line="${BLUE}${ICON_ARROW}${NC} ${badge}${name}" + if [[ -n "$desc" ]]; then + line+=" ${GRAY}- ${desc}${NC}" + fi - if ${first_heading:-true}; then - first_heading=false - else - echo "" - fi + if ${first_heading:-true}; then + first_heading=false + else + echo "" + fi - echo -e "$line" + echo -e "$line" } touchid_configured() { - local pam_file="/etc/pam.d/sudo" - [[ -f "$pam_file" ]] && grep -q "pam_tid.so" "$pam_file" 2> /dev/null + local pam_file="/etc/pam.d/sudo" + [[ -f "$pam_file" ]] && grep -q "pam_tid.so" "$pam_file" 2> /dev/null } touchid_supported() { - if command -v bioutil > /dev/null 2>&1; then - bioutil -r 2> /dev/null | grep -q "Touch ID" && return 0 - fi - [[ "$(uname -m)" == "arm64" ]] + if command -v bioutil > /dev/null 2>&1; then + bioutil -r 2> /dev/null | grep -q "Touch ID" && return 0 + fi + [[ "$(uname -m)" == "arm64" ]] } cleanup_path() { - local raw_path="$1" - local label="$2" + local raw_path="$1" + local label="$2" - local expanded_path="${raw_path/#\~/$HOME}" - if [[ ! -e "$expanded_path" ]]; then - echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label" - return - fi + local expanded_path="${raw_path/#\~/$HOME}" + if [[ ! -e "$expanded_path" ]]; then + echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label" + return + fi - local size_kb - size_kb=$(du -sk "$expanded_path" 2> /dev/null | awk '{print $1}' || echo "0") - local size_display="" - if [[ "$size_kb" =~ ^[0-9]+$ && "$size_kb" -gt 0 ]]; then - size_display=$(bytes_to_human "$((size_kb * 1024))") - fi + local size_kb + size_kb=$(du -sk "$expanded_path" 2> /dev/null | awk '{print $1}' || echo "0") + local size_display="" + if [[ "$size_kb" =~ ^[0-9]+$ && "$size_kb" -gt 0 ]]; then + size_display=$(bytes_to_human "$((size_kb * 1024))") + fi - if rm -rf "$expanded_path"; then - if [[ -n "$size_display" ]]; then - echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label ${GREEN}(${size_display})${NC}" - else - echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label" - fi - else - echo -e " ${RED}${ICON_ERROR}${NC} Failed to remove $label" - fi + if rm -rf "$expanded_path"; then + if [[ -n "$size_display" ]]; then + echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label ${GREEN}(${size_display})${NC}" + else + echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label" + fi + else + echo -e " ${RED}${ICON_ERROR}${NC} Failed to remove $label" + fi } ensure_directory() { - local raw_path="$1" - local expanded_path="${raw_path/#\~/$HOME}" - mkdir -p "$expanded_path" > /dev/null 2>&1 || true + local raw_path="$1" + local expanded_path="${raw_path/#\~/$HOME}" + mkdir -p "$expanded_path" > /dev/null 2>&1 || true } list_login_items() { - local raw_items - raw_items=$(osascript -e 'tell application "System Events" to get the name of every login item' 2> /dev/null || echo "") - [[ -z "$raw_items" || "$raw_items" == "missing value" ]] && return + local raw_items + raw_items=$(osascript -e 'tell application "System Events" to get the name of every login item' 2> /dev/null || echo "") + [[ -z "$raw_items" || "$raw_items" == "missing value" ]] && return - IFS=',' read -ra login_items_array <<< "$raw_items" - for entry in "${login_items_array[@]}"; do - local trimmed - trimmed=$(echo "$entry" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//') - [[ -n "$trimmed" ]] && printf "%s\n" "$trimmed" - done + IFS=',' read -ra login_items_array <<< "$raw_items" + for entry in "${login_items_array[@]}"; do + local trimmed + trimmed=$(echo "$entry" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//') + [[ -n "$trimmed" ]] && printf "%s\n" "$trimmed" + done } SUDO_KEEPALIVE_PID="" start_sudo_keepalive() { - [[ -n "$SUDO_KEEPALIVE_PID" ]] && return + [[ -n "$SUDO_KEEPALIVE_PID" ]] && return - ( - while true; do - if ! sudo -n true 2> /dev/null; then - exit 0 - fi - sleep 30 - done - ) & - SUDO_KEEPALIVE_PID=$! + ( + while true; do + if ! sudo -n true 2> /dev/null; then + exit 0 + fi + sleep 30 + done + ) & + SUDO_KEEPALIVE_PID=$! } stop_sudo_keepalive() { - if [[ -n "$SUDO_KEEPALIVE_PID" ]]; then - kill "$SUDO_KEEPALIVE_PID" 2> /dev/null || true - wait "$SUDO_KEEPALIVE_PID" 2> /dev/null || true - SUDO_KEEPALIVE_PID="" - fi + if [[ -n "$SUDO_KEEPALIVE_PID" ]]; then + kill "$SUDO_KEEPALIVE_PID" 2> /dev/null || true + wait "$SUDO_KEEPALIVE_PID" 2> /dev/null || true + SUDO_KEEPALIVE_PID="" + fi } trap stop_sudo_keepalive EXIT count_local_snapshots() { - if ! command -v tmutil > /dev/null 2>&1; then - echo 0 - return - fi + if ! command -v tmutil > /dev/null 2>&1; then + echo 0 + return + fi - local output - output=$(tmutil listlocalsnapshots / 2> /dev/null || true) - if [[ -z "$output" ]]; then - echo 0 - return - fi + local output + output=$(tmutil listlocalsnapshots / 2> /dev/null || true) + if [[ -z "$output" ]]; then + echo 0 + return + fi - echo "$output" | grep -c "com.apple.TimeMachine." | tr -d ' ' + echo "$output" | grep -c "com.apple.TimeMachine." | tr -d ' ' } execute_optimization() { - local action="$1" - local path="$2" + local action="$1" + local path="$2" - case "$action" in - system_maintenance) - echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding LaunchServices database..." - timeout 10 /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user > /dev/null 2>&1 || true - echo -e "${GREEN}${ICON_SUCCESS}${NC} LaunchServices database rebuilt" + case "$action" in + system_maintenance) + echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding LaunchServices database..." + timeout 10 /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user > /dev/null 2>&1 || true + echo -e "${GREEN}${ICON_SUCCESS}${NC} LaunchServices database rebuilt" - echo -e "${BLUE}${ICON_ARROW}${NC} Flushing DNS cache..." - if sudo dscacheutil -flushcache 2> /dev/null && sudo killall -HUP mDNSResponder 2> /dev/null; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} DNS cache flushed" - else - echo -e "${RED}${ICON_ERROR}${NC} Failed to flush DNS cache" - fi + echo -e "${BLUE}${ICON_ARROW}${NC} Flushing DNS cache..." + if sudo dscacheutil -flushcache 2> /dev/null && sudo killall -HUP mDNSResponder 2> /dev/null; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} DNS cache flushed" + else + echo -e "${RED}${ICON_ERROR}${NC} Failed to flush DNS cache" + fi - echo -e "${BLUE}${ICON_ARROW}${NC} Purging memory cache..." - if sudo purge 2> /dev/null; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Memory cache purged" - else - echo -e "${RED}${ICON_ERROR}${NC} Failed to purge memory" - fi + echo -e "${BLUE}${ICON_ARROW}${NC} Purging memory cache..." + if sudo purge 2> /dev/null; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Memory cache purged" + else + echo -e "${RED}${ICON_ERROR}${NC} Failed to purge memory" + fi - echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding font cache..." - sudo atsutil databases -remove > /dev/null 2>&1 - echo -e "${GREEN}${ICON_SUCCESS}${NC} Font cache rebuilt" + echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding font cache..." + sudo atsutil databases -remove > /dev/null 2>&1 + echo -e "${GREEN}${ICON_SUCCESS}${NC} Font cache rebuilt" - echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding Spotlight index..." - sudo mdutil -E / > /dev/null 2>&1 || true - echo -e "${GREEN}${ICON_SUCCESS}${NC} Spotlight index rebuilt" - ;; + echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding Spotlight index..." + sudo mdutil -E / > /dev/null 2>&1 || true + echo -e "${GREEN}${ICON_SUCCESS}${NC} Spotlight index rebuilt" + ;; - startup_items) - echo -e "${BLUE}${ICON_ARROW}${NC} Opening Launch Agents directory..." - open ~/Library/LaunchAgents - open /Library/LaunchAgents - echo -e "${GREEN}${ICON_SUCCESS}${NC} Please review and disable unnecessary startup items" - echo -e "${GRAY} Tip: Move unwanted .plist files to trash${NC}" - ;; + startup_items) + echo -e "${BLUE}${ICON_ARROW}${NC} Opening Launch Agents directory..." + open ~/Library/LaunchAgents + open /Library/LaunchAgents + echo -e "${GREEN}${ICON_SUCCESS}${NC} Please review and disable unnecessary startup items" + echo -e "${GRAY} Tip: Move unwanted .plist files to trash${NC}" + ;; - network_services) - echo -e "${BLUE}${ICON_ARROW}${NC} Resetting network services..." - if sudo dscacheutil -flushcache 2> /dev/null && sudo killall -HUP mDNSResponder 2> /dev/null; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Network services reset" - else - echo -e "${RED}${ICON_ERROR}${NC} Failed to reset network services" - fi - ;; + network_services) + echo -e "${BLUE}${ICON_ARROW}${NC} Resetting network services..." + if sudo dscacheutil -flushcache 2> /dev/null && sudo killall -HUP mDNSResponder 2> /dev/null; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Network services reset" + else + echo -e "${RED}${ICON_ERROR}${NC} Failed to reset network services" + fi + ;; - cache_refresh) - echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Quick Look cache..." - qlmanage -r cache > /dev/null 2>&1 || true - qlmanage -r > /dev/null 2>&1 || true + cache_refresh) + echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Quick Look cache..." + qlmanage -r cache > /dev/null 2>&1 || true + qlmanage -r > /dev/null 2>&1 || true - local -a cache_targets=( - "$HOME/Library/Caches/com.apple.QuickLook.thumbnailcache|Quick Look thumbnails" - "$HOME/Library/Caches/com.apple.iconservices.store|Icon Services store" - "$HOME/Library/Caches/com.apple.iconservices|Icon Services cache" - "$HOME/Library/Caches/com.apple.Safari/WebKitCache|Safari WebKit cache" - "$HOME/Library/Caches/com.apple.Safari/Favicon|Safari favicon cache" - ) + local -a cache_targets=( + "$HOME/Library/Caches/com.apple.QuickLook.thumbnailcache|Quick Look thumbnails" + "$HOME/Library/Caches/com.apple.iconservices.store|Icon Services store" + "$HOME/Library/Caches/com.apple.iconservices|Icon Services cache" + "$HOME/Library/Caches/com.apple.Safari/WebKitCache|Safari WebKit cache" + "$HOME/Library/Caches/com.apple.Safari/Favicon|Safari favicon cache" + ) - for target in "${cache_targets[@]}"; do - IFS='|' read -r target_path label <<< "$target" - cleanup_path "$target_path" "$label" - done + for target in "${cache_targets[@]}"; do + IFS='|' read -r target_path label <<< "$target" + cleanup_path "$target_path" "$label" + done - echo -e "${GREEN}${ICON_SUCCESS}${NC} Finder and Safari caches refreshed" - ;; + echo -e "${GREEN}${ICON_SUCCESS}${NC} Finder and Safari caches refreshed" + ;; - maintenance_scripts) - echo -e "${BLUE}${ICON_ARROW}${NC} Running macOS periodic scripts..." - local periodic_cmd="/usr/sbin/periodic" - if [[ -x "$periodic_cmd" ]]; then - local periodic_output="" - if periodic_output=$(sudo "$periodic_cmd" daily weekly monthly 2>&1); then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Daily/weekly/monthly scripts completed" - else - echo -e "${YELLOW}!${NC} periodic scripts reported an issue" - printf '%s\n' "$periodic_output" | sed 's/^/ /' - fi - fi + maintenance_scripts) + echo -e "${BLUE}${ICON_ARROW}${NC} Running macOS periodic scripts..." + local periodic_cmd="/usr/sbin/periodic" + if [[ -x "$periodic_cmd" ]]; then + local periodic_output="" + if periodic_output=$(sudo "$periodic_cmd" daily weekly monthly 2>&1); then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Daily/weekly/monthly scripts completed" + else + echo -e "${YELLOW}!${NC} periodic scripts reported an issue" + printf '%s\n' "$periodic_output" | sed 's/^/ /' + fi + fi - echo -e "${BLUE}${ICON_ARROW}${NC} Rotating system logs..." - if sudo newsyslog > /dev/null 2>&1; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Log rotation complete" - else - echo -e "${YELLOW}!${NC} newsyslog reported an issue" - fi + echo -e "${BLUE}${ICON_ARROW}${NC} Rotating system logs..." + if sudo newsyslog > /dev/null 2>&1; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Log rotation complete" + else + echo -e "${YELLOW}!${NC} newsyslog reported an issue" + fi - if [[ -x "/usr/libexec/repair_packages" ]]; then - echo -e "${BLUE}${ICON_ARROW}${NC} Repairing base system permissions..." - if sudo /usr/libexec/repair_packages --repair --standard-pkgs --volume / > /dev/null 2>&1; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Base system permission repair complete" - else - echo -e "${YELLOW}!${NC} repair_packages reported an issue" - fi - fi - ;; + if [[ -x "/usr/libexec/repair_packages" ]]; then + echo -e "${BLUE}${ICON_ARROW}${NC} Repairing base system permissions..." + if sudo /usr/libexec/repair_packages --repair --standard-pkgs --volume / > /dev/null 2>&1; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Base system permission repair complete" + else + echo -e "${YELLOW}!${NC} repair_packages reported an issue" + fi + fi + ;; - log_cleanup) - echo -e "${BLUE}${ICON_ARROW}${NC} Clearing diagnostic & crash logs..." - local -a user_logs=( - "$HOME/Library/Logs/DiagnosticReports" - "$HOME/Library/Logs/CrashReporter" - "$HOME/Library/Logs/corecaptured" - ) - for target in "${user_logs[@]}"; do - cleanup_path "$target" "$(basename "$target")" - done + log_cleanup) + echo -e "${BLUE}${ICON_ARROW}${NC} Clearing diagnostic & crash logs..." + local -a user_logs=( + "$HOME/Library/Logs/DiagnosticReports" + "$HOME/Library/Logs/CrashReporter" + "$HOME/Library/Logs/corecaptured" + ) + for target in "${user_logs[@]}"; do + cleanup_path "$target" "$(basename "$target")" + done - if [[ -d "/Library/Logs/DiagnosticReports" ]]; then - sudo find /Library/Logs/DiagnosticReports -type f -name "*.crash" -delete 2> /dev/null || true - sudo find /Library/Logs/DiagnosticReports -type f -name "*.panic" -delete 2> /dev/null || true - echo -e " ${GREEN}${ICON_SUCCESS}${NC} System diagnostic logs cleared" - else - echo -e " ${GRAY}-${NC} No system diagnostic logs found" - fi - ;; + if [[ -d "/Library/Logs/DiagnosticReports" ]]; then + sudo find /Library/Logs/DiagnosticReports -type f -name "*.crash" -delete 2> /dev/null || true + sudo find /Library/Logs/DiagnosticReports -type f -name "*.panic" -delete 2> /dev/null || true + echo -e " ${GREEN}${ICON_SUCCESS}${NC} System diagnostic logs cleared" + else + echo -e " ${GRAY}-${NC} No system diagnostic logs found" + fi + ;; - recent_items) - echo -e "${BLUE}${ICON_ARROW}${NC} Clearing recent items lists..." - local shared_dir="$HOME/Library/Application Support/com.apple.sharedfilelist" - if [[ -d "$shared_dir" ]]; then - local removed - removed=$(find "$shared_dir" -name "*.sfl2" -type f -print -delete 2> /dev/null | wc -l | tr -d ' ') - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Reset $removed shared file lists" - else - echo -e " ${GRAY}-${NC} Recent item caches already clean" - fi + recent_items) + echo -e "${BLUE}${ICON_ARROW}${NC} Clearing recent items lists..." + local shared_dir="$HOME/Library/Application Support/com.apple.sharedfilelist" + if [[ -d "$shared_dir" ]]; then + local removed + removed=$(find "$shared_dir" -name "*.sfl2" -type f -print -delete 2> /dev/null | wc -l | tr -d ' ') + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Reset $removed shared file lists" + else + echo -e " ${GRAY}-${NC} Recent item caches already clean" + fi - rm -f "$HOME/Library/Preferences/com.apple.recentitems.plist" 2> /dev/null || true - defaults delete NSGlobalDomain NSRecentDocumentsLimit 2> /dev/null || true - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Finder/Apple menu recent items cleared" - ;; + rm -f "$HOME/Library/Preferences/com.apple.recentitems.plist" 2> /dev/null || true + defaults delete NSGlobalDomain NSRecentDocumentsLimit 2> /dev/null || true + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Finder/Apple menu recent items cleared" + ;; - radio_refresh) - echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Bluetooth preferences..." - rm -f "$HOME/Library/Preferences/com.apple.Bluetooth.plist" 2> /dev/null || true - sudo rm -f /Library/Preferences/com.apple.Bluetooth.plist 2> /dev/null || true - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Bluetooth caches refreshed" + radio_refresh) + echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Bluetooth preferences..." + rm -f "$HOME/Library/Preferences/com.apple.Bluetooth.plist" 2> /dev/null || true + sudo rm -f /Library/Preferences/com.apple.Bluetooth.plist 2> /dev/null || true + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Bluetooth caches refreshed" - echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Wi-Fi configuration..." - local sysconfig="/Library/Preferences/SystemConfiguration" - if [[ -d "$sysconfig" ]]; then - sudo cp "$sysconfig"/com.apple.airport.preferences.plist "$sysconfig"/com.apple.airport.preferences.plist.bak 2> /dev/null || true - sudo rm -f "$sysconfig"/com.apple.airport.preferences.plist "$sysconfig"/NetworkInterfaces.plist "$sysconfig"/preferences.plist 2> /dev/null || true - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Wi-Fi preferences reset" - else - echo -e " ${GRAY}-${NC} SystemConfiguration directory missing" - fi + echo -e "${BLUE}${ICON_ARROW}${NC} Resetting Wi-Fi configuration..." + local sysconfig="/Library/Preferences/SystemConfiguration" + if [[ -d "$sysconfig" ]]; then + sudo cp "$sysconfig"/com.apple.airport.preferences.plist "$sysconfig"/com.apple.airport.preferences.plist.bak 2> /dev/null || true + sudo rm -f "$sysconfig"/com.apple.airport.preferences.plist "$sysconfig"/NetworkInterfaces.plist "$sysconfig"/preferences.plist 2> /dev/null || true + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Wi-Fi preferences reset" + else + echo -e " ${GRAY}-${NC} SystemConfiguration directory missing" + fi - sudo ifconfig awdl0 down 2> /dev/null || true - sudo ifconfig awdl0 up 2> /dev/null || true - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Wireless services refreshed" - ;; + sudo ifconfig awdl0 down 2> /dev/null || true + sudo ifconfig awdl0 up 2> /dev/null || true + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Wireless services refreshed" + ;; - mail_downloads) - echo -e "${BLUE}${ICON_ARROW}${NC} Clearing Mail attachment downloads..." - local -a mail_dirs=( - "$HOME/Library/Mail Downloads|Mail Downloads" - "$HOME/Library/Containers/com.apple.mail/Data/Library/Mail Downloads|Mail Container Downloads" - ) - for target in "${mail_dirs[@]}"; do - IFS='|' read -r target_path label <<< "$target" - cleanup_path "$target_path" "$label" - ensure_directory "$target_path" - done - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Mail downloads cleared" - ;; + mail_downloads) + echo -e "${BLUE}${ICON_ARROW}${NC} Clearing Mail attachment downloads..." + local -a mail_dirs=( + "$HOME/Library/Mail Downloads|Mail Downloads" + "$HOME/Library/Containers/com.apple.mail/Data/Library/Mail Downloads|Mail Container Downloads" + ) + for target in "${mail_dirs[@]}"; do + IFS='|' read -r target_path label <<< "$target" + cleanup_path "$target_path" "$label" + ensure_directory "$target_path" + done + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Mail downloads cleared" + ;; - saved_state_cleanup) - echo -e "${BLUE}${ICON_ARROW}${NC} Purging saved application states..." - local state_dir="$HOME/Library/Saved Application State" - cleanup_path "$state_dir" "Saved Application State" - ensure_directory "$state_dir" - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Saved states cleared" - ;; + saved_state_cleanup) + echo -e "${BLUE}${ICON_ARROW}${NC} Purging saved application states..." + local state_dir="$HOME/Library/Saved Application State" + cleanup_path "$state_dir" "Saved Application State" + ensure_directory "$state_dir" + echo -e " ${GREEN}${ICON_SUCCESS}${NC} Saved states cleared" + ;; - 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 - killall Finder > /dev/null 2>&1 || true - killall Dock > /dev/null 2>&1 || true - echo -e " ${GREEN}${ICON_SUCCESS}${NC} Finder & Dock relaunched" - ;; + 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 + 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) - echo -e "${BLUE}${ICON_ARROW}${NC} Flushing memory caches..." - if sudo purge > /dev/null 2>&1; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Inactive memory purged" - else - echo -e "${YELLOW}!${NC} purge command failed" - fi + swap_cleanup) + echo -e "${BLUE}${ICON_ARROW}${NC} Flushing memory caches..." + if sudo purge > /dev/null 2>&1; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Inactive memory purged" + else + echo -e "${YELLOW}!${NC} purge command failed" + fi - echo -e "${BLUE}${ICON_ARROW}${NC} Stopping dynamic pager and removing swapfiles..." - if sudo launchctl unload /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist > /dev/null 2>&1; then - sudo rm -f /private/var/vm/swapfile* > /dev/null 2>&1 || true - sudo touch /private/var/vm/swapfile0 > /dev/null 2>&1 || true - sudo chmod 600 /private/var/vm/swapfile0 > /dev/null 2>&1 || true - sudo launchctl load /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist > /dev/null 2>&1 || true - echo -e "${GREEN}${ICON_SUCCESS}${NC} Swap cache rebuilt" - else - echo -e "${YELLOW}!${NC} Could not unload dynamic_pager" - fi - ;; + echo -e "${BLUE}${ICON_ARROW}${NC} Stopping dynamic pager and removing swapfiles..." + if sudo launchctl unload /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist > /dev/null 2>&1; then + sudo rm -f /private/var/vm/swapfile* > /dev/null 2>&1 || true + sudo touch /private/var/vm/swapfile0 > /dev/null 2>&1 || true + sudo chmod 600 /private/var/vm/swapfile0 > /dev/null 2>&1 || true + sudo launchctl load /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist > /dev/null 2>&1 || true + echo -e "${GREEN}${ICON_SUCCESS}${NC} Swap cache rebuilt" + else + echo -e "${YELLOW}!${NC} Could not unload dynamic_pager" + fi + ;; - startup_cache) - echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding kext caches..." - if sudo kextcache -i / > /dev/null 2>&1; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Kernel/kext caches rebuilt" - else - echo -e "${YELLOW}!${NC} kextcache reported an issue" - fi + startup_cache) + echo -e "${BLUE}${ICON_ARROW}${NC} Rebuilding kext caches..." + if sudo kextcache -i / > /dev/null 2>&1; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Kernel/kext caches rebuilt" + else + echo -e "${YELLOW}!${NC} kextcache reported an issue" + fi - echo -e "${BLUE}${ICON_ARROW}${NC} Clearing system prelinked kernel caches..." - sudo rm -rf /System/Library/PrelinkedKernels/* > /dev/null 2>&1 || true - sudo kextcache -system-prelinked-kernel > /dev/null 2>&1 || true - echo -e "${GREEN}${ICON_SUCCESS}${NC} Startup caches refreshed" - ;; + echo -e "${BLUE}${ICON_ARROW}${NC} Clearing system prelinked kernel caches..." + sudo rm -rf /System/Library/PrelinkedKernels/* > /dev/null 2>&1 || true + sudo kextcache -system-prelinked-kernel > /dev/null 2>&1 || true + echo -e "${GREEN}${ICON_SUCCESS}${NC} Startup caches refreshed" + ;; - local_snapshots) - if ! command -v tmutil > /dev/null 2>&1; then - echo -e "${YELLOW}!${NC} tmutil not available on this system" - return - fi + local_snapshots) + if ! command -v tmutil > /dev/null 2>&1; then + echo -e "${YELLOW}!${NC} tmutil not available on this system" + return + fi - local before after - before=$(count_local_snapshots) - if [[ "$before" -eq 0 ]]; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} No local snapshots to thin" - return - fi + local before after + before=$(count_local_snapshots) + if [[ "$before" -eq 0 ]]; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} No local snapshots to thin" + return + fi - echo -e "${BLUE}${ICON_ARROW}${NC} Thinning $before APFS local snapshots..." - if sudo tmutil thinlocalsnapshots / 9999999999 4 > /dev/null 2>&1; then - after=$(count_local_snapshots) - local removed=$((before - after)) - if [[ "$removed" -lt 0 ]]; then - removed=0 - fi - echo -e "${GREEN}${ICON_SUCCESS}${NC} Removed $removed snapshots (remaining: $after)" - else - echo -e "${RED}${ICON_ERROR}${NC} Failed to thin local snapshots" - fi - ;; + echo -e "${BLUE}${ICON_ARROW}${NC} Thinning $before APFS local snapshots..." + if sudo tmutil thinlocalsnapshots / 9999999999 4 > /dev/null 2>&1; then + after=$(count_local_snapshots) + local removed=$((before - after)) + if [[ "$removed" -lt 0 ]]; then + removed=0 + fi + echo -e "${GREEN}${ICON_SUCCESS}${NC} Removed $removed snapshots (remaining: $after)" + else + echo -e "${RED}${ICON_ERROR}${NC} Failed to thin local snapshots" + fi + ;; - developer_cleanup) - local -a dev_targets=( - "$HOME/Library/Developer/Xcode/DerivedData|Xcode DerivedData" - "$HOME/Library/Developer/Xcode/Archives|Build archives" - "$HOME/Library/Developer/Xcode/iOS DeviceSupport|iOS Device support files" - "$HOME/Library/Developer/CoreSimulator/Caches|CoreSimulator caches" - ) + developer_cleanup) + local -a dev_targets=( + "$HOME/Library/Developer/Xcode/DerivedData|Xcode DerivedData" + "$HOME/Library/Developer/Xcode/Archives|Build archives" + "$HOME/Library/Developer/Xcode/iOS DeviceSupport|iOS Device support files" + "$HOME/Library/Developer/CoreSimulator/Caches|CoreSimulator caches" + ) - for target in "${dev_targets[@]}"; do - IFS='|' read -r target_path label <<< "$target" - cleanup_path "$target_path" "$label" - done + for target in "${dev_targets[@]}"; do + IFS='|' read -r target_path label <<< "$target" + cleanup_path "$target_path" "$label" + done - if command -v xcrun > /dev/null 2>&1; then - echo -e "${BLUE}${ICON_ARROW}${NC} Removing unavailable simulator runtimes..." - if xcrun simctl delete unavailable > /dev/null 2>&1; then - echo -e "${GREEN}${ICON_SUCCESS}${NC} Unavailable simulators removed" - else - echo -e "${YELLOW}!${NC} Could not prune simulator runtimes" - fi - fi + if command -v xcrun > /dev/null 2>&1; then + echo -e "${BLUE}${ICON_ARROW}${NC} Removing unavailable simulator runtimes..." + if xcrun simctl delete unavailable > /dev/null 2>&1; then + echo -e "${GREEN}${ICON_SUCCESS}${NC} Unavailable simulators removed" + else + echo -e "${YELLOW}!${NC} Could not prune simulator runtimes" + fi + fi - echo -e "${GREEN}${ICON_SUCCESS}${NC} Developer caches cleaned" - ;; + echo -e "${GREEN}${ICON_SUCCESS}${NC} Developer caches cleaned" + ;; - *) - echo -e "${RED}${ICON_ERROR}${NC} Unknown action: $action" - ;; - esac + *) + echo -e "${RED}${ICON_ERROR}${NC} Unknown action: $action" + ;; + esac } main() { - if [[ -t 1 ]]; then - clear - fi - print_header + if [[ -t 1 ]]; then + clear + fi + print_header - # Check dependencies - if ! command -v jq > /dev/null 2>&1; then - log_error "jq is required but not installed. Install with: brew install jq" - exit 1 - fi + # Check dependencies + if ! command -v jq > /dev/null 2>&1; then + log_error "jq is required but not installed. Install with: brew install jq" + exit 1 + fi - if ! command -v bc > /dev/null 2>&1; then - log_error "bc is required but not installed. Install with: brew install bc" - exit 1 - fi + if ! command -v bc > /dev/null 2>&1; then + log_error "bc is required but not installed. Install with: brew install bc" + exit 1 + fi - # Collect system health data using pure Bash implementation - local health_json - if ! health_json=$(generate_health_json 2> /dev/null); then - log_error "Failed to collect system health data" - exit 1 - fi + # Collect system health data using pure Bash implementation + local health_json + if ! health_json=$(generate_health_json 2> /dev/null); then + log_error "Failed to collect system health data" + exit 1 + fi - # Show system health - show_system_health "$health_json" + # Show system health + show_system_health "$health_json" - # Parse and display optimizations - local -a safe_items=() - local -a confirm_items=() + # Parse and display optimizations + local -a safe_items=() + local -a confirm_items=() - while IFS= read -r opt_json; do - [[ -z "$opt_json" ]] && continue + while IFS= read -r opt_json; do + [[ -z "$opt_json" ]] && continue - local name=$(echo "$opt_json" | jq -r '.name') - local desc=$(echo "$opt_json" | jq -r '.description') - local action=$(echo "$opt_json" | jq -r '.action') - local path=$(echo "$opt_json" | jq -r '.path // ""') - local safe=$(echo "$opt_json" | jq -r '.safe') + local name=$(echo "$opt_json" | jq -r '.name') + local desc=$(echo "$opt_json" | jq -r '.description') + local action=$(echo "$opt_json" | jq -r '.action') + local path=$(echo "$opt_json" | jq -r '.path // ""') + local safe=$(echo "$opt_json" | jq -r '.safe') - local item="${name}|${desc}|${action}|${path}" + local item="${name}|${desc}|${action}|${path}" - if [[ "$safe" == "true" ]]; then - safe_items+=("$item") - else - confirm_items+=("$item") - fi - done < <(parse_optimizations "$health_json") + if [[ "$safe" == "true" ]]; then + safe_items+=("$item") + else + confirm_items+=("$item") + fi + done < <(parse_optimizations "$health_json") - # Simple confirmation with sudo context - echo -ne "${PURPLE}${ICON_ARROW}${NC} System optimizations need admin access — ${GREEN}Enter${NC} Touch ID/password, ${GRAY}ESC${NC} cancel: " + # Simple confirmation with sudo context + echo -ne "${PURPLE}${ICON_ARROW}${NC} System optimizations need admin access — ${GREEN}Enter${NC} Touch ID/password, ${GRAY}ESC${NC} cancel: " - IFS= read -r -s -n1 key || key="" - drain_pending_input # Clean up any escape sequence remnants - case "$key" in - $'\e' | q | Q) - echo "" - echo "" - echo -e "${GRAY}Cancelled${NC}" - echo "" - exit 0 - ;; - "" | $'\n' | $'\r') - printf "\r\033[K" - if ! request_sudo_access "System optimizations require admin access"; then - echo "" - echo -e "${YELLOW}Authentication failed${NC}" - exit 1 - fi - start_sudo_keepalive - ;; - *) - echo "" - echo "" - echo -e "${GRAY}Cancelled${NC}" - echo "" - exit 0 - ;; - esac + IFS= read -r -s -n1 key || key="" + drain_pending_input # Clean up any escape sequence remnants + case "$key" in + $'\e' | q | Q) + echo "" + echo "" + echo -e "${GRAY}Cancelled${NC}" + echo "" + exit 0 + ;; + "" | $'\n' | $'\r') + printf "\r\033[K" + if ! request_sudo_access "System optimizations require admin access"; then + echo "" + echo -e "${YELLOW}Authentication failed${NC}" + exit 1 + fi + start_sudo_keepalive + ;; + *) + echo "" + echo "" + echo -e "${GRAY}Cancelled${NC}" + echo "" + exit 0 + ;; + esac - # Execute all optimizations - local first_heading=true + # Execute all optimizations + local first_heading=true - # Run safe optimizations - if [[ ${#safe_items[@]} -gt 0 ]]; then - for item in "${safe_items[@]}"; do - IFS='|' read -r name desc action path <<< "$item" - announce_action "$name" "$desc" "safe" - execute_optimization "$action" "$path" - done - fi + # Run safe optimizations + if [[ ${#safe_items[@]} -gt 0 ]]; then + for item in "${safe_items[@]}"; do + IFS='|' read -r name desc action path <<< "$item" + announce_action "$name" "$desc" "safe" + execute_optimization "$action" "$path" + done + fi - # Run confirm items - if [[ ${#confirm_items[@]} -gt 0 ]]; then - for item in "${confirm_items[@]}"; do - IFS='|' read -r name desc action path <<< "$item" - announce_action "$name" "$desc" "confirm" - execute_optimization "$action" "$path" - done - fi + # Run confirm items + if [[ ${#confirm_items[@]} -gt 0 ]]; then + for item in "${confirm_items[@]}"; do + IFS='|' read -r name desc action path <<< "$item" + announce_action "$name" "$desc" "confirm" + execute_optimization "$action" "$path" + done + fi - # Show login item reminder at the end of optimization log - local -a login_items_list=() - while IFS= read -r login_item; do - [[ -n "$login_item" ]] && login_items_list+=("$login_item") - done < <(list_login_items || true) + # Show login item reminder at the end of optimization log + local -a login_items_list=() + while IFS= read -r login_item; do + [[ -n "$login_item" ]] && login_items_list+=("$login_item") + done < <(list_login_items || true) - if (( ${#login_items_list[@]} > 0 )); then - local display_count=${#login_items_list[@]} - echo "" - echo -e "${BLUE}${ICON_ARROW}${NC} Login items (${display_count}) auto-start at login:" - local preview_limit=5 - (( preview_limit > display_count )) && preview_limit=$display_count - for ((i = 0; i < preview_limit; i++)); do - printf " • %s\n" "${login_items_list[$i]}" - done - if (( display_count > preview_limit )); then - local remaining=$((display_count - preview_limit)) - echo " • …and $remaining more" - fi - echo -e "${GRAY}Review System Settings → General → Login Items to trim extras.${NC}" - fi + if ((${#login_items_list[@]} > 0)); then + local display_count=${#login_items_list[@]} + echo "" + echo -e "${BLUE}${ICON_ARROW}${NC} Login items (${display_count}) auto-start at login:" + local preview_limit=5 + ((preview_limit > display_count)) && preview_limit=$display_count + for ((i = 0; i < preview_limit; i++)); do + printf " • %s\n" "${login_items_list[$i]}" + done + if ((display_count > preview_limit)); then + local remaining=$((display_count - preview_limit)) + echo " • …and $remaining more" + fi + echo -e "${GRAY}Review System Settings → General → Login Items to trim extras.${NC}" + fi - echo "" - local summary_title="System optimization completed" - local -a summary_details=() + echo "" + local summary_title="System optimization completed" + local -a summary_details=() - local safe_count=${#safe_items[@]} - local confirm_count=${#confirm_items[@]} - if (( safe_count > 0 )); then - summary_details+=("Automations: ${GREEN}${safe_count}${NC} sections optimized end-to-end.") - else - summary_details+=("Automations: No automated changes were necessary.") - fi + local safe_count=${#safe_items[@]} + local confirm_count=${#confirm_items[@]} + if ((safe_count > 0)); then + summary_details+=("Automations: ${GREEN}${safe_count}${NC} sections optimized end-to-end.") + else + summary_details+=("Automations: No automated changes were necessary.") + fi - if (( confirm_count > 0 )); then - summary_details+=("Follow-ups: ${YELLOW}${confirm_count}${NC} manual checks suggested (see log).") - fi + if ((confirm_count > 0)); then + summary_details+=("Follow-ups: ${YELLOW}${confirm_count}${NC} manual checks suggested (see log).") + fi - summary_details+=("Highlights: caches refreshed, services restarted, startup assets rebuilt.") - summary_details+=("Result: system responsiveness should feel lighter.") + summary_details+=("Highlights: caches refreshed, services restarted, startup assets rebuilt.") + summary_details+=("Result: system responsiveness should feel lighter.") - local show_touchid_tip="false" - if touchid_supported && ! touchid_configured; then - show_touchid_tip="true" - fi + local show_touchid_tip="false" + if touchid_supported && ! touchid_configured; then + show_touchid_tip="true" + fi - if [[ "$show_touchid_tip" == "true" ]]; then - echo -e "Tip: run 'mo touchid' to approve sudo via Touch ID." - fi - print_summary_block "success" "$summary_title" "${summary_details[@]}" - printf '\n' + if [[ "$show_touchid_tip" == "true" ]]; then + echo -e "Tip: run 'mo touchid' to approve sudo via Touch ID." + fi + print_summary_block "success" "$summary_title" "${summary_details[@]}" + printf '\n' } main "$@" diff --git a/bin/uninstall.sh b/bin/uninstall.sh index 3364b9a..fc9f732 100755 --- a/bin/uninstall.sh +++ b/bin/uninstall.sh @@ -100,42 +100,18 @@ format_last_used_summary() { # Scan applications and collect information scan_applications() { - # Cache configuration + # Simplified cache: only check timestamp (24h TTL) local cache_dir="$HOME/.cache/mole" local cache_file="$cache_dir/app_scan_cache" - local cache_meta="$cache_dir/app_scan_meta" - local cache_dir_mtime="$cache_dir/app_dir_mtime" - local cache_ttl=86400 # 24 hours cache validity (app count change will trigger refresh) + local cache_ttl=86400 # 24 hours mkdir -p "$cache_dir" 2> /dev/null - # Get modification time of app directories to detect new installations - local sys_app_mtime - sys_app_mtime=$(stat -f%m "/Applications" 2> /dev/null || echo "0") - local user_app_mtime - user_app_mtime=$(stat -f%m "$HOME/Applications" 2> /dev/null || echo "0") - local combined_mtime=$((sys_app_mtime + user_app_mtime)) - - # Quick count of current apps (system + user directories) - local current_app_count - current_app_count=$( - ( - find /Applications -name "*.app" -maxdepth 1 2> /dev/null - find ~/Applications -name "*.app" -maxdepth 1 2> /dev/null - ) | wc -l | tr -d ' ' - ) - - # Check if cache is valid unless explicitly disabled - if [[ -f "$cache_file" && -f "$cache_meta" && -f "$cache_dir_mtime" ]]; then - local cache_age=$(($(date +%s) - $(stat -f%m "$cache_file" 2> /dev/null || echo 0))) - local cached_app_count - cached_app_count=$(cat "$cache_meta" 2> /dev/null || echo "0") - local cached_dir_mtime - cached_dir_mtime=$(cat "$cache_dir_mtime" 2> /dev/null || echo "0") - - # Cache is valid if: age < TTL AND app count matches AND directory not modified - if [[ $cache_age -lt $cache_ttl && "$cached_app_count" == "$current_app_count" && "$cached_dir_mtime" == "$combined_mtime" ]]; then - # Silent - cache hit, return immediately without any output + # Check if cache exists and is fresh + if [[ -f "$cache_file" ]]; then + local cache_age=$(($(date +%s) - $(stat -f%m "$cache_file" 2> /dev/null || echo 86401))) + if [[ $cache_age -lt $cache_ttl ]]; then + # Cache hit - return immediately echo "$cache_file" return 0 fi @@ -381,12 +357,10 @@ scan_applications() { } rm -f "$temp_file" - # Update cache with app count metadata and directory modification time + # Save to cache (simplified - no metadata) cp "${temp_file}.sorted" "$cache_file" 2> /dev/null || true - echo "$current_app_count" > "$cache_meta" 2> /dev/null || true - echo "$combined_mtime" > "$cache_dir_mtime" 2> /dev/null || true - # Verify sorted file exists before returning + # Return sorted file if [[ -f "${temp_file}.sorted" ]]; then echo "${temp_file}.sorted" else @@ -613,20 +587,13 @@ main() { # Hide cursor during operation hide_cursor - # Quick cache validity check first (minimal I/O) - local cache_dir="$HOME/.cache/mole" - local cache_file="$cache_dir/app_scan_cache" - local cache_meta="$cache_dir/app_scan_meta" - local cache_ttl=86400 + # Simplified: always check if we need alt screen for scanning + # (scan_applications handles cache internally) local needs_scanning=true - - # Fast preliminary check: cache exists and not expired - if [[ -f "$cache_file" && -f "$cache_meta" ]]; then + local cache_file="$HOME/.cache/mole/app_scan_cache" + if [[ -f "$cache_file" ]]; then local cache_age=$(($(date +%s) - $(stat -f%m "$cache_file" 2> /dev/null || echo 86401))) - if [[ $cache_age -lt $cache_ttl ]]; then - # Cache age is OK, now check app count (delegate to scan_applications) - needs_scanning=false - fi + [[ $cache_age -lt 86400 ]] && needs_scanning=false fi # Only enter alt screen if we need scanning (shows progress) diff --git a/lib/optimize_health.sh b/lib/optimize_health.sh index a183a05..d16e66c 100755 --- a/lib/optimize_health.sh +++ b/lib/optimize_health.sh @@ -9,12 +9,12 @@ get_memory_info() { local total_bytes used_gb total_gb # Total memory - total_bytes=$(sysctl -n hw.memsize 2>/dev/null || echo "0") + total_bytes=$(sysctl -n hw.memsize 2> /dev/null || echo "0") total_gb=$(awk "BEGIN {printf \"%.2f\", $total_bytes / (1024*1024*1024)}") # Used memory from vm_stat local vm_output active wired compressed page_size - vm_output=$(vm_stat 2>/dev/null || echo "") + vm_output=$(vm_stat 2> /dev/null || echo "") page_size=4096 active=$(echo "$vm_output" | awk '/Pages active:/ {print $NF}' | tr -d '.') @@ -25,7 +25,7 @@ get_memory_info() { wired=${wired:-0} compressed=${compressed:-0} - local used_bytes=$(( (active + wired + compressed) * page_size )) + local used_bytes=$(((active + wired + compressed) * page_size)) used_gb=$(awk "BEGIN {printf \"%.2f\", $used_bytes / (1024*1024*1024)}") echo "$used_gb $total_gb" @@ -36,7 +36,7 @@ get_disk_info() { local home="${HOME:-/}" local df_output total_gb used_gb used_percent - df_output=$(df -k "$home" 2>/dev/null | tail -1) + df_output=$(df -k "$home" 2> /dev/null | tail -1) local total_kb used_kb total_kb=$(echo "$df_output" | awk '{print $2}') @@ -53,7 +53,7 @@ get_disk_info() { get_uptime_days() { local boot_output boot_time uptime_days - boot_output=$(sysctl -n kern.boottime 2>/dev/null || echo "") + boot_output=$(sysctl -n kern.boottime 2> /dev/null || echo "") boot_time=$(echo "$boot_output" | sed -n 's/.*sec = \([0-9]*\).*/\1/p') if [[ -n "$boot_time" ]]; then @@ -71,7 +71,7 @@ get_uptime_days() { dir_size_kb() { local path="$1" [[ ! -e "$path" ]] && echo "0" && return - du -sk "$path" 2>/dev/null | awk '{print $1}' || echo "0" + du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0" } # Format size from KB @@ -101,7 +101,7 @@ check_startup_items() { ) for dir in "${dirs[@]}"; do - [[ -d "$dir" ]] && count=$((count + $(ls -1 "$dir" 2>/dev/null | wc -l))) + [[ -d "$dir" ]] && count=$((count + $(ls -1 "$dir" 2> /dev/null | wc -l))) done if [[ $count -gt 5 ]]; then @@ -160,7 +160,7 @@ check_swap_cleanup() { local file for file in /private/var/vm/swapfile*; do - [[ -f "$file" ]] && total_kb=$((total_kb + $(stat -f%z "$file" 2>/dev/null || echo 0) / 1024)) + [[ -f "$file" ]] && total_kb=$((total_kb + $(stat -f%z "$file" 2> /dev/null || echo 0) / 1024)) done if [[ $total_kb -gt 0 ]]; then @@ -171,13 +171,13 @@ check_swap_cleanup() { # Check local snapshots check_local_snapshots() { - command -v tmutil >/dev/null 2>&1 || return + command -v tmutil > /dev/null 2>&1 || return local snapshots - snapshots=$(tmutil listlocalsnapshots / 2>/dev/null || echo "") + snapshots=$(tmutil listlocalsnapshots / 2> /dev/null || echo "") local count - count=$(echo "$snapshots" | grep -c "com.apple.TimeMachine" 2>/dev/null) + count=$(echo "$snapshots" | grep -c "com.apple.TimeMachine" 2> /dev/null) count=$(echo "$count" | tr -d ' \n') count=${count:-0} [[ "$count" =~ ^[0-9]+$ ]] && [[ $count -gt 0 ]] && echo "local_snapshots|Local Snapshots|${count} APFS local snapshots detected|true" @@ -237,13 +237,20 @@ EOF # Conditional items local item - item=$(check_startup_items || true); [[ -n "$item" ]] && items+=("$item") - item=$(check_cache_refresh || true); [[ -n "$item" ]] && items+=("$item") - item=$(check_mail_downloads || true); [[ -n "$item" ]] && items+=("$item") - item=$(check_saved_state || true); [[ -n "$item" ]] && items+=("$item") - item=$(check_swap_cleanup || true); [[ -n "$item" ]] && items+=("$item") - item=$(check_local_snapshots || true); [[ -n "$item" ]] && items+=("$item") - item=$(check_developer_cleanup || true); [[ -n "$item" ]] && items+=("$item") + item=$(check_startup_items || true) + [[ -n "$item" ]] && items+=("$item") + item=$(check_cache_refresh || true) + [[ -n "$item" ]] && items+=("$item") + item=$(check_mail_downloads || true) + [[ -n "$item" ]] && items+=("$item") + item=$(check_saved_state || true) + [[ -n "$item" ]] && items+=("$item") + item=$(check_swap_cleanup || true) + [[ -n "$item" ]] && items+=("$item") + item=$(check_local_snapshots || true) + [[ -n "$item" ]] && items+=("$item") + item=$(check_developer_cleanup || true) + [[ -n "$item" ]] && items+=("$item") # Output items as JSON local first=true diff --git a/scripts/check.sh b/scripts/check.sh index 64ed74a..4e1a102 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -67,13 +67,13 @@ echo -e "${YELLOW}4. Checking code optimizations...${NC}" OPTIMIZATION_SCORE=0 TOTAL_CHECKS=0 -# Check 1: Simplified keyboard input (0.05s timeout) +# Check 1: Keyboard input handling (restored to 1s for reliability) ((TOTAL_CHECKS++)) -if grep -q "read -r -s -n 1 -t 0.05" lib/common.sh; then - echo -e "${GREEN} ✓ Keyboard timeout optimized (0.05s)${NC}" +if grep -q "read -r -s -n 1 -t 1" lib/common.sh; then + echo -e "${GREEN} ✓ Keyboard timeout properly configured (1s)${NC}" ((OPTIMIZATION_SCORE++)) else - echo -e "${YELLOW} ⚠ Keyboard timeout not optimized${NC}" + echo -e "${YELLOW} ⚠ Keyboard timeout may be misconfigured${NC}" fi # Check 2: Single-pass drain_pending_input