mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 14:26:46 +00:00
feat: add new system optimization tasks and implement orphaned startup item cleanup
This commit is contained in:
@@ -33,7 +33,7 @@ fix_broken_preferences() {
|
||||
plutil -lint "$plist_file" > /dev/null 2>&1 && continue
|
||||
|
||||
# Remove broken plist
|
||||
rm -f "$plist_file" 2> /dev/null || true
|
||||
safe_remove "$plist_file" true > /dev/null 2>&1 || true
|
||||
((broken_count++))
|
||||
done < <(command find "$prefs_dir" -maxdepth 1 -name "*.plist" -type f 2> /dev/null || true)
|
||||
|
||||
@@ -53,7 +53,7 @@ fix_broken_preferences() {
|
||||
|
||||
plutil -lint "$plist_file" > /dev/null 2>&1 && continue
|
||||
|
||||
rm -f "$plist_file" 2> /dev/null || true
|
||||
safe_remove "$plist_file" true > /dev/null 2>&1 || true
|
||||
((broken_count++))
|
||||
done < <(command find "$byhost_dir" -name "*.plist" -type f 2> /dev/null || true)
|
||||
fi
|
||||
@@ -61,54 +61,4 @@ fix_broken_preferences() {
|
||||
echo "$broken_count"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Broken Login Items Cleanup
|
||||
# Find and remove login items pointing to non-existent files
|
||||
# ============================================================================
|
||||
|
||||
# Clean login items with missing executables
|
||||
fix_broken_login_items() {
|
||||
local launch_agents_dir="$HOME/Library/LaunchAgents"
|
||||
[[ -d "$launch_agents_dir" ]] || return 0
|
||||
|
||||
# Check whitelist
|
||||
if command -v is_whitelisted > /dev/null && is_whitelisted "check_login_items"; then return 0; fi
|
||||
|
||||
local broken_count=0
|
||||
|
||||
while IFS= read -r plist_file; do
|
||||
[[ -f "$plist_file" ]] || continue
|
||||
|
||||
# Skip system items
|
||||
local filename
|
||||
filename=$(basename "$plist_file")
|
||||
case "$filename" in
|
||||
com.apple.*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
# Extract Program or ProgramArguments[0] from plist using plutil
|
||||
local program=""
|
||||
program=$(plutil -extract Program raw "$plist_file" 2> /dev/null || echo "")
|
||||
|
||||
if [[ -z "$program" ]]; then
|
||||
# Try ProgramArguments array (first element)
|
||||
program=$(plutil -extract ProgramArguments.0 raw "$plist_file" 2> /dev/null || echo "")
|
||||
fi
|
||||
|
||||
# Expand tilde in path if present
|
||||
program="${program/#\~/$HOME}"
|
||||
|
||||
# Skip if no program found or program exists
|
||||
[[ -z "$program" ]] && continue
|
||||
[[ -e "$program" ]] && continue
|
||||
|
||||
# Program doesn't exist - this is a broken login item
|
||||
launchctl unload "$plist_file" 2> /dev/null || true
|
||||
rm -f "$plist_file" 2> /dev/null || true
|
||||
((broken_count++))
|
||||
done < <(command find "$launch_agents_dir" -name "*.plist" -type f 2> /dev/null || true)
|
||||
|
||||
echo "$broken_count"
|
||||
}
|
||||
|
||||
@@ -12,7 +12,11 @@ readonly MOLE_TM_THIN_TIMEOUT=180
|
||||
readonly MOLE_TM_THIN_VALUE=9999999999
|
||||
|
||||
flush_dns_cache() {
|
||||
sudo dscacheutil -flushcache 2> /dev/null && sudo killall -HUP mDNSResponder 2> /dev/null
|
||||
if sudo dscacheutil -flushcache 2> /dev/null && sudo killall -HUP mDNSResponder 2> /dev/null; then
|
||||
MOLE_DNS_FLUSHED=1
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Rebuild databases and flush caches
|
||||
@@ -38,7 +42,8 @@ opt_system_maintenance() {
|
||||
done
|
||||
}
|
||||
|
||||
# Refresh Finder and Safari caches
|
||||
# Refresh Finder caches (QuickLook and icon services)
|
||||
# Note: Safari caches are cleaned separately in clean/user.sh, so excluded here
|
||||
opt_cache_refresh() {
|
||||
qlmanage -r cache > /dev/null 2>&1 || true
|
||||
qlmanage -r > /dev/null 2>&1 || true
|
||||
@@ -48,8 +53,6 @@ opt_cache_refresh() {
|
||||
"$HOME/Library/Caches/com.apple.QuickLook.thumbnailcache"
|
||||
"$HOME/Library/Caches/com.apple.iconservices.store"
|
||||
"$HOME/Library/Caches/com.apple.iconservices"
|
||||
"$HOME/Library/Caches/com.apple.Safari/WebKitCache"
|
||||
"$HOME/Library/Caches/com.apple.Safari/Favicon"
|
||||
)
|
||||
|
||||
for target_path in "${cache_targets[@]}"; do
|
||||
@@ -64,50 +67,11 @@ opt_cache_refresh() {
|
||||
|
||||
echo -e " ${GREEN}✓${NC} QuickLook thumbnails refreshed"
|
||||
echo -e " ${GREEN}✓${NC} Icon services cache rebuilt"
|
||||
echo -e " ${GREEN}✓${NC} Safari web cache optimized"
|
||||
}
|
||||
|
||||
# Run periodic maintenance scripts
|
||||
opt_maintenance_scripts() {
|
||||
if [[ -t 1 ]]; then
|
||||
MOLE_SPINNER_PREFIX=" " start_inline_spinner "Rotating logs..."
|
||||
fi
|
||||
# Removed: opt_maintenance_scripts - macOS handles log rotation automatically via launchd
|
||||
|
||||
local success=false
|
||||
if run_with_timeout 120 sudo newsyslog > /dev/null 2>&1; then
|
||||
success=true
|
||||
fi
|
||||
|
||||
if [[ -t 1 ]]; then
|
||||
stop_inline_spinner
|
||||
fi
|
||||
|
||||
if [[ "$success" == "true" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} System logs rotated"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to rotate logs"
|
||||
fi
|
||||
}
|
||||
|
||||
# Refresh wireless interfaces
|
||||
opt_radio_refresh() {
|
||||
# Only restart Bluetooth service, do NOT delete pairing information
|
||||
if sudo pkill -HUP bluetoothd 2> /dev/null; then
|
||||
echo -e " ${GREEN}✓${NC} Bluetooth controller refreshed"
|
||||
fi
|
||||
|
||||
local wifi_interface
|
||||
wifi_interface=$(networksetup -listallhardwareports | awk '/Wi-Fi/{getline; print $2}' | head -1)
|
||||
if [[ -n "$wifi_interface" ]]; then
|
||||
if sudo bash -c "trap '' INT TERM; ifconfig '$wifi_interface' down; sleep 1; ifconfig '$wifi_interface' up" 2> /dev/null; then
|
||||
echo -e " ${GREEN}✓${NC} Wi-Fi interface reset"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restart AirDrop interface
|
||||
sudo bash -c "trap '' INT TERM; ifconfig awdl0 down; ifconfig awdl0 up" 2> /dev/null || true
|
||||
echo -e " ${GREEN}✓${NC} AirDrop service restarted"
|
||||
}
|
||||
# Removed: opt_radio_refresh - Interrupts active user connections (WiFi, Bluetooth), degrading UX
|
||||
|
||||
# Saved state: remove OLD app saved states (7+ days)
|
||||
opt_saved_state_cleanup() {
|
||||
@@ -125,47 +89,416 @@ opt_saved_state_cleanup() {
|
||||
echo -e " ${GREEN}✓${NC} App saved states optimized"
|
||||
}
|
||||
|
||||
# Swap cleanup: reset swap files
|
||||
opt_swap_cleanup() {
|
||||
if sudo launchctl unload /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist > /dev/null 2>&1; then
|
||||
sudo launchctl load /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist > /dev/null 2>&1 || true
|
||||
echo -e " ${GREEN}✓${NC} Swap cache reset"
|
||||
# Removed: opt_swap_cleanup - Direct virtual memory operations pose system crash risk
|
||||
|
||||
# Removed: opt_startup_cache - Modern macOS has no such mechanism
|
||||
|
||||
# Removed: opt_local_snapshots - Deletes user Time Machine recovery points, breaks backup continuity
|
||||
|
||||
opt_fix_broken_configs() {
|
||||
local broken_prefs=$(fix_broken_preferences)
|
||||
|
||||
if [[ $broken_prefs -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Repaired $broken_prefs corrupted preference files"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to reset swap"
|
||||
echo -e " ${GREEN}✓${NC} All preference files valid"
|
||||
fi
|
||||
}
|
||||
|
||||
# Startup cache: rebuild kernel caches (handled automatically by modern macOS)
|
||||
opt_startup_cache() {
|
||||
echo -e " ${GRAY}-${NC} Startup cache (auto-managed by macOS)"
|
||||
# Network cache optimization
|
||||
opt_network_optimization() {
|
||||
if [[ "${MOLE_DNS_FLUSHED:-0}" == "1" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} DNS cache already refreshed"
|
||||
echo -e " ${GREEN}✓${NC} mDNSResponder already restarted"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if flush_dns_cache; then
|
||||
echo -e " ${GREEN}✓${NC} DNS cache refreshed"
|
||||
echo -e " ${GREEN}✓${NC} mDNSResponder restarted"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to refresh DNS cache"
|
||||
fi
|
||||
}
|
||||
|
||||
# Local snapshots: thin Time Machine snapshots
|
||||
opt_local_snapshots() {
|
||||
if ! command -v tmutil > /dev/null 2>&1; then
|
||||
echo -e "${YELLOW}!${NC} tmutil not available on this system"
|
||||
return
|
||||
# SQLite database vacuum optimization
|
||||
# Compresses and optimizes SQLite databases for Mail, Messages, Safari
|
||||
opt_sqlite_vacuum() {
|
||||
if ! command -v sqlite3 > /dev/null 2>&1; then
|
||||
echo -e " ${GRAY}-${NC} sqlite3 not available, skipping database optimization"
|
||||
return 0
|
||||
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
|
||||
local -a busy_apps=()
|
||||
local -a check_apps=("Mail" "Safari" "Messages")
|
||||
local app
|
||||
for app in "${check_apps[@]}"; do
|
||||
if pgrep -x "$app" > /dev/null 2>&1; then
|
||||
busy_apps+=("$app")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#busy_apps[@]} -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}!${NC} Close these apps before database optimization: ${busy_apps[*]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local -a db_paths=(
|
||||
"$HOME/Library/Mail/V*/MailData/Envelope Index*"
|
||||
"$HOME/Library/Messages/chat.db"
|
||||
"$HOME/Library/Safari/History.db"
|
||||
"$HOME/Library/Safari/TopSites.db"
|
||||
)
|
||||
|
||||
local vacuumed=0
|
||||
local timed_out=0
|
||||
local failed=0
|
||||
|
||||
for pattern in "${db_paths[@]}"; do
|
||||
while IFS= read -r db_file; do
|
||||
[[ ! -f "$db_file" ]] && continue
|
||||
[[ "$db_file" == *"-wal" || "$db_file" == *"-shm" ]] && continue
|
||||
|
||||
# Skip if protected
|
||||
should_protect_path "$db_file" && continue
|
||||
|
||||
# Verify it's a SQLite database
|
||||
if ! file "$db_file" 2>/dev/null | grep -q "SQLite"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Try to vacuum
|
||||
local exit_code=0
|
||||
set +e
|
||||
run_with_timeout 20 sqlite3 "$db_file" "VACUUM;" 2>/dev/null
|
||||
exit_code=$?
|
||||
set -e
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
((vacuumed++))
|
||||
elif [[ $exit_code -eq 124 ]]; then
|
||||
((timed_out++))
|
||||
else
|
||||
((failed++))
|
||||
fi
|
||||
done < <(compgen -G "$pattern" || true)
|
||||
done
|
||||
|
||||
if [[ $vacuumed -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Optimized $vacuumed databases for Mail, Safari, Messages"
|
||||
elif [[ $timed_out -eq 0 && $failed -eq 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} All databases already optimized"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Database optimization incomplete"
|
||||
fi
|
||||
|
||||
if [[ $timed_out -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}!${NC} Timed out on $timed_out databases"
|
||||
fi
|
||||
|
||||
if [[ $failed -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}!${NC} Failed on $failed databases"
|
||||
fi
|
||||
}
|
||||
|
||||
# LaunchServices database rebuild
|
||||
# Fixes "Open with" menu issues, duplicate apps, broken file associations
|
||||
opt_launch_services_rebuild() {
|
||||
if [[ -t 1 ]]; then
|
||||
start_inline_spinner ""
|
||||
fi
|
||||
|
||||
local lsregister="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"
|
||||
|
||||
if [[ -f "$lsregister" ]]; then
|
||||
local success=0
|
||||
set +e
|
||||
"$lsregister" -r -domain local -domain user -domain system > /dev/null 2>&1
|
||||
success=$?
|
||||
if [[ $success -ne 0 ]]; then
|
||||
"$lsregister" -r -domain local -domain user > /dev/null 2>&1
|
||||
success=$?
|
||||
fi
|
||||
set -e
|
||||
|
||||
if [[ -t 1 ]]; then
|
||||
stop_inline_spinner
|
||||
fi
|
||||
|
||||
if [[ $success -eq 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} LaunchServices repaired"
|
||||
echo -e " ${GREEN}✓${NC} File associations refreshed"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to rebuild LaunchServices"
|
||||
fi
|
||||
else
|
||||
if [[ -t 1 ]]; then
|
||||
stop_inline_spinner
|
||||
fi
|
||||
echo -e " ${YELLOW}!${NC} lsregister not found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Font cache rebuild
|
||||
# Fixes font rendering issues, missing fonts, and character display problems
|
||||
opt_font_cache_rebuild() {
|
||||
local success=false
|
||||
|
||||
if sudo atsutil databases -remove > /dev/null 2>&1; then
|
||||
success=true
|
||||
fi
|
||||
|
||||
if [[ "$success" == "true" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Font cache cleared"
|
||||
echo -e " ${GREEN}✓${NC} System will rebuild font database automatically"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to clear font cache"
|
||||
fi
|
||||
}
|
||||
|
||||
# Startup items cleanup
|
||||
# Removes broken LaunchAgents and analyzes startup performance impact
|
||||
opt_startup_items_cleanup() {
|
||||
# Check whitelist (respects 'Login items check' setting)
|
||||
if command -v is_whitelisted > /dev/null && is_whitelisted "check_login_items"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local -a scan_dirs=(
|
||||
"$HOME/Library/LaunchAgents"
|
||||
"$HOME/Library/LaunchDaemons"
|
||||
"/Library/LaunchAgents"
|
||||
"/Library/LaunchDaemons"
|
||||
)
|
||||
|
||||
local broken_count=0
|
||||
local total_count=0
|
||||
local processed_files=0
|
||||
|
||||
for dir in "${scan_dirs[@]}"; do
|
||||
[[ ! -d "$dir" ]] && continue
|
||||
|
||||
# Check if we need sudo for this directory
|
||||
local need_sudo=false
|
||||
if [[ "$dir" == "/Library"* ]]; then
|
||||
need_sudo=true
|
||||
fi
|
||||
|
||||
# Process plists
|
||||
local find_cmd=(find)
|
||||
if [[ "$need_sudo" == "true" ]]; then
|
||||
find_cmd=(sudo find)
|
||||
fi
|
||||
|
||||
while IFS= read -r plist_file; do
|
||||
# Verify file exists (unless in test mode)
|
||||
if [[ -z "${MO_TEST_MODE:-}" && ! -f "$plist_file" ]]; then
|
||||
continue
|
||||
fi
|
||||
((total_count++))
|
||||
|
||||
# Skip system items (com.apple.*)
|
||||
local filename=$(basename "$plist_file")
|
||||
[[ "$filename" == com.apple.* ]] && continue
|
||||
|
||||
# Check if plist is valid (use sudo for system dirs)
|
||||
local lint_output=""
|
||||
local lint_status=0
|
||||
local errexit_was_set=0
|
||||
[[ $- == *e* ]] && errexit_was_set=1
|
||||
set +e
|
||||
if [[ "$need_sudo" == "true" ]]; then
|
||||
lint_output=$(sudo plutil -lint "$plist_file" 2>&1)
|
||||
lint_status=$?
|
||||
else
|
||||
lint_output=$(plutil -lint "$plist_file" 2>&1)
|
||||
lint_status=$?
|
||||
fi
|
||||
if [[ $errexit_was_set -eq 1 ]]; then
|
||||
set -e
|
||||
fi
|
||||
|
||||
if [[ $lint_status -ne 0 ]]; then
|
||||
# Skip if lint failed due to permissions or transient read errors
|
||||
if echo "$lint_output" | grep -qi "permission\\|operation not permitted\\|not permitted"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Invalid plist - remove it
|
||||
if command -v should_protect_path > /dev/null && should_protect_path "$plist_file"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$need_sudo" == "true" ]]; then
|
||||
sudo launchctl unload "$plist_file" 2>/dev/null || true
|
||||
if safe_sudo_remove "$plist_file"; then
|
||||
((broken_count++))
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to remove (sudo) $plist_file"
|
||||
fi
|
||||
else
|
||||
launchctl unload "$plist_file" 2>/dev/null || true
|
||||
if safe_remove "$plist_file" true; then
|
||||
((broken_count++))
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to remove $plist_file"
|
||||
fi
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract program path
|
||||
local program=""
|
||||
program=$(plutil -extract Program raw "$plist_file" 2>/dev/null || echo "")
|
||||
|
||||
if [[ -z "$program" ]]; then
|
||||
program=$(plutil -extract ProgramArguments.0 raw "$plist_file" 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
program="${program/#\~/$HOME}"
|
||||
|
||||
# Skip paths with variables or non-absolute program definitions
|
||||
if [[ "$program" == *'$'* || "$program" != /* ]]; then
|
||||
continue
|
||||
fi
|
||||
# Check for orphaned privileged helpers (app uninstalled but helper remains)
|
||||
local associated_bundle=""
|
||||
associated_bundle=$(plutil -extract AssociatedBundleIdentifiers.0 raw "$plist_file" 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$associated_bundle" ]]; then
|
||||
# Check if the associated app exists
|
||||
local app_path=""
|
||||
# First check standard locations
|
||||
if [[ -d "/Applications/$associated_bundle.app" ]]; then
|
||||
app_path="/Applications/$associated_bundle.app"
|
||||
elif [[ -d "$HOME/Applications/$associated_bundle.app" ]]; then
|
||||
app_path="$HOME/Applications/$associated_bundle.app"
|
||||
else
|
||||
# Fallback to mdfind (slower but comprehensive, with 10s timeout)
|
||||
app_path=$(run_with_timeout 10 mdfind "kMDItemCFBundleIdentifier == '$associated_bundle'" 2>/dev/null | head -1 || echo "")
|
||||
fi
|
||||
|
||||
# If associated app is MISSING, this is an orphan
|
||||
if [[ -z "$app_path" ]]; then
|
||||
if command -v should_protect_path > /dev/null && should_protect_path "$plist_file"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get the helper tool path
|
||||
local program=""
|
||||
program=$(plutil -extract Program raw "$plist_file" 2>/dev/null || echo "")
|
||||
if [[ -z "$program" ]]; then
|
||||
program=$(plutil -extract ProgramArguments.0 raw "$plist_file" 2>/dev/null || echo "")
|
||||
fi
|
||||
program="${program/#\~/$HOME}"
|
||||
|
||||
# Double check we are not deleting system files
|
||||
if [[ "$program" == /System/* ||
|
||||
"$program" == /usr/lib/* ||
|
||||
"$program" == /usr/bin/* ||
|
||||
"$program" == /usr/sbin/* ||
|
||||
"$program" == /Library/Apple/* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$need_sudo" == "true" ]]; then
|
||||
sudo launchctl unload "$plist_file" 2>/dev/null || true
|
||||
# remove the plist
|
||||
safe_sudo_remove "$plist_file"
|
||||
|
||||
# AND remove the helper binary if it exists and is not protected
|
||||
if [[ -n "$program" && -f "$program" ]]; then
|
||||
safe_sudo_remove "$program"
|
||||
fi
|
||||
((broken_count++))
|
||||
echo -e " ${GREEN}✓${NC} Removed orphaned helper: $(basename "$program")"
|
||||
else
|
||||
launchctl unload "$plist_file" 2>/dev/null || true
|
||||
safe_remove "$plist_file" true
|
||||
if [[ -n "$program" && -f "$program" ]]; then
|
||||
safe_remove "$program" true
|
||||
fi
|
||||
((broken_count++))
|
||||
echo -e " ${GREEN}✓${NC} Removed orphaned helper: $(basename "$program")"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# If program doesn't exist, remove the launch agent/daemon
|
||||
if [[ -n "$program" && ! -e "$program" ]]; then
|
||||
if command -v should_protect_path > /dev/null && should_protect_path "$plist_file"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$need_sudo" == "true" ]]; then
|
||||
sudo launchctl unload "$plist_file" 2>/dev/null || true
|
||||
if safe_sudo_remove "$plist_file"; then
|
||||
((broken_count++))
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to remove (sudo) $plist_file"
|
||||
fi
|
||||
else
|
||||
launchctl unload "$plist_file" 2>/dev/null || true
|
||||
if safe_remove "$plist_file" true; then
|
||||
((broken_count++))
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Failed to remove $plist_file"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < <("${find_cmd[@]}" "$dir" -maxdepth 1 -name "*.plist" -type f 2>/dev/null || true)
|
||||
done
|
||||
|
||||
if [[ $broken_count -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Removed $broken_count broken startup items"
|
||||
fi
|
||||
|
||||
if [[ $total_count -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Verified $total_count startup items"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} No startup items found"
|
||||
fi
|
||||
}
|
||||
|
||||
# dyld shared cache update
|
||||
# Rebuilds dynamic linker shared cache to improve app launch speed
|
||||
# Only beneficial after new app installations or system updates
|
||||
opt_dyld_cache_update() {
|
||||
# Check if command exists
|
||||
if ! command -v update_dyld_shared_cache > /dev/null 2>&1; then
|
||||
echo -e " ${GRAY}-${NC} dyld cache (automatically managed by macOS)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Skip if dyld cache was already rebuilt recently (within 24 hours)
|
||||
local dyld_cache_path="/var/db/dyld/dyld_shared_cache_$(uname -m)"
|
||||
if [[ -e "$dyld_cache_path" ]]; then
|
||||
local cache_mtime
|
||||
cache_mtime=$(stat -f "%m" "$dyld_cache_path" 2>/dev/null || echo "0")
|
||||
local current_time
|
||||
current_time=$(date +%s)
|
||||
local time_diff=$((current_time - cache_mtime))
|
||||
local one_day_seconds=$((24 * 3600))
|
||||
|
||||
if [[ $time_diff -lt $one_day_seconds ]]; then
|
||||
echo -e " ${GREEN}✓${NC} dyld shared cache already up-to-date"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -t 1 ]]; then
|
||||
start_inline_spinner "Rebuilding dyld cache..."
|
||||
fi
|
||||
|
||||
local success=false
|
||||
local exit_code=0
|
||||
# This can take 1-2 minutes on some systems (180 second timeout)
|
||||
set +e
|
||||
run_with_timeout "$MOLE_TM_THIN_TIMEOUT" sudo tmutil thinlocalsnapshots / "$MOLE_TM_THIN_VALUE" 4 > /dev/null 2>&1
|
||||
run_with_timeout 180 sudo update_dyld_shared_cache -force > /dev/null 2>&1
|
||||
exit_code=$?
|
||||
set -e
|
||||
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
success=true
|
||||
fi
|
||||
|
||||
@@ -173,51 +506,82 @@ opt_local_snapshots() {
|
||||
stop_inline_spinner
|
||||
fi
|
||||
|
||||
after=$(count_local_snapshots)
|
||||
local removed=$((before - after))
|
||||
[[ "$removed" -lt 0 ]] && removed=0
|
||||
|
||||
if [[ "$success" == "true" ]]; then
|
||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Removed $removed snapshots (remaining: $after)"
|
||||
elif [[ "$exit_code" -eq 124 ]]; then
|
||||
echo -e "${YELLOW}!${NC} Timed out after ${MOLE_TM_THIN_TIMEOUT}s"
|
||||
echo -e " ${GREEN}✓${NC} dyld shared cache rebuilt"
|
||||
echo -e " ${GREEN}✓${NC} App launch speed improved"
|
||||
elif [[ $exit_code -eq 124 ]]; then
|
||||
echo -e " ${YELLOW}!${NC} dyld cache update timed out"
|
||||
else
|
||||
echo -e "${YELLOW}!${NC} Failed with exit code $exit_code"
|
||||
echo -e " ${GRAY}-${NC} dyld cache update skipped (automatically managed)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fix broken system configurations
|
||||
# Repairs corrupted preference files and broken login items
|
||||
opt_fix_broken_configs() {
|
||||
local broken_prefs=$(fix_broken_preferences)
|
||||
local broken_items=$(fix_broken_login_items)
|
||||
# System services refresh
|
||||
# Restarts system services to apply cache and configuration changes
|
||||
opt_system_services_refresh() {
|
||||
local -a restarted_services=()
|
||||
|
||||
if [[ $broken_prefs -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Repaired $broken_prefs corrupted preference files"
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} All preference files valid"
|
||||
# cfprefsd - Preferences cache daemon (ensures fixed preferences take effect)
|
||||
if killall -HUP cfprefsd 2>/dev/null; then
|
||||
restarted_services+=("Preferences")
|
||||
fi
|
||||
|
||||
if [[ $broken_items -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Removed $broken_items broken login items"
|
||||
# lsd - LaunchServices daemon (ensures rebuild takes effect)
|
||||
if killall lsd 2>/dev/null; then
|
||||
restarted_services+=("LaunchServices")
|
||||
fi
|
||||
|
||||
# iconservicesagent - Icon services (ensures cache refresh takes effect)
|
||||
if killall iconservicesagent 2>/dev/null; then
|
||||
restarted_services+=("Icon Services")
|
||||
fi
|
||||
|
||||
# fontd - Font server (ensures font cache refresh takes effect)
|
||||
if killall fontd 2>/dev/null; then
|
||||
restarted_services+=("Font Server")
|
||||
fi
|
||||
|
||||
if [[ ${#restarted_services[@]} -gt 0 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Refreshed ${#restarted_services[@]} system services"
|
||||
for service in "${restarted_services[@]}"; do
|
||||
echo -e " • $service"
|
||||
done
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} All login items functional"
|
||||
echo -e " ${GREEN}✓${NC} System services already optimal"
|
||||
fi
|
||||
}
|
||||
|
||||
# Network cache optimization
|
||||
opt_network_optimization() {
|
||||
flush_dns_cache
|
||||
echo -e " ${GREEN}✓${NC} DNS cache refreshed"
|
||||
# Dock cache refresh
|
||||
# Fixes broken icons, duplicate items, and visual glitches in the Dock
|
||||
opt_dock_refresh() {
|
||||
local dock_support="$HOME/Library/Application Support/Dock"
|
||||
local refreshed=false
|
||||
|
||||
if sudo arp -d -a > /dev/null 2>&1; then
|
||||
echo -e " ${GREEN}✓${NC} ARP cache rebuilt"
|
||||
# Remove Dock database files (icons, positions, etc.)
|
||||
if [[ -d "$dock_support" ]]; then
|
||||
while IFS= read -r db_file; do
|
||||
if [[ -f "$db_file" ]]; then
|
||||
safe_remove "$db_file" true > /dev/null 2>&1 && refreshed=true
|
||||
fi
|
||||
done < <(find "$dock_support" -name "*.db" -type f 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
echo -e " ${GREEN}✓${NC} mDNSResponder optimized"
|
||||
# Also clear Dock plist cache
|
||||
local dock_plist="$HOME/Library/Preferences/com.apple.dock.plist"
|
||||
if [[ -f "$dock_plist" ]]; then
|
||||
# Just touch to invalidate cache, don't delete (preserves user settings)
|
||||
touch "$dock_plist" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Restart Dock to apply changes
|
||||
killall Dock 2>/dev/null || true
|
||||
|
||||
if [[ "$refreshed" == "true" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} Dock cache cleared"
|
||||
fi
|
||||
echo -e " ${GREEN}✓${NC} Dock refreshed"
|
||||
}
|
||||
|
||||
# Clean Spotlight user caches
|
||||
|
||||
# Execute optimization by action name
|
||||
execute_optimization() {
|
||||
@@ -227,14 +591,16 @@ execute_optimization() {
|
||||
case "$action" in
|
||||
system_maintenance) opt_system_maintenance ;;
|
||||
cache_refresh) opt_cache_refresh ;;
|
||||
maintenance_scripts) opt_maintenance_scripts ;;
|
||||
radio_refresh) opt_radio_refresh ;;
|
||||
saved_state_cleanup) opt_saved_state_cleanup ;;
|
||||
swap_cleanup) opt_swap_cleanup ;;
|
||||
startup_cache) opt_startup_cache ;;
|
||||
local_snapshots) opt_local_snapshots ;;
|
||||
fix_broken_configs) opt_fix_broken_configs ;;
|
||||
network_optimization) opt_network_optimization ;;
|
||||
sqlite_vacuum) opt_sqlite_vacuum ;;
|
||||
launch_services_rebuild) opt_launch_services_rebuild ;;
|
||||
font_cache_rebuild) opt_font_cache_rebuild ;;
|
||||
startup_items_cleanup) opt_startup_items_cleanup ;;
|
||||
dyld_cache_update) opt_dyld_cache_update ;;
|
||||
system_services_refresh) opt_system_services_refresh ;;
|
||||
dock_refresh) opt_dock_refresh ;;
|
||||
*)
|
||||
echo -e "${YELLOW}${ICON_ERROR}${NC} Unknown action: $action"
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user