mirror of
https://github.com/tw93/Mole.git
synced 2026-02-11 02:29:19 +00:00
Merge branch 'dev' into fix/harden-brew-uninstall
This commit is contained in:
@@ -32,24 +32,6 @@ clean_empty_library_items() {
|
||||
safe_clean "${empty_dirs[@]}" "Empty Library folders"
|
||||
fi
|
||||
|
||||
# Clean empty files in Library root (skipping .localized and other sentinels)
|
||||
local -a empty_files=()
|
||||
while IFS= read -r -d '' file; do
|
||||
[[ -f "$file" ]] || continue
|
||||
# Protect .localized and potential system sentinels
|
||||
if [[ "$(basename "$file")" == ".localized" ]]; then
|
||||
continue
|
||||
fi
|
||||
if is_path_whitelisted "$file"; then
|
||||
continue
|
||||
fi
|
||||
empty_files+=("$file")
|
||||
done < <(find "$HOME/Library" -mindepth 1 -maxdepth 1 -type f -empty -print0 2> /dev/null)
|
||||
|
||||
if [[ ${#empty_files[@]} -gt 0 ]]; then
|
||||
safe_clean "${empty_files[@]}" "Empty Library files"
|
||||
fi
|
||||
|
||||
# 2. Clean empty subdirectories in Application Support and other key locations
|
||||
# Iteratively remove empty directories until no more are found
|
||||
local -a key_locations=(
|
||||
@@ -102,8 +84,8 @@ clean_chrome_old_versions() {
|
||||
"$HOME/Applications/Google Chrome.app"
|
||||
)
|
||||
|
||||
# Use -f to match Chrome Helper processes as well
|
||||
if pgrep -f "Google Chrome" > /dev/null 2>&1; then
|
||||
# Match the exact Chrome process name to avoid false positives
|
||||
if pgrep -x "Google Chrome" > /dev/null 2>&1; then
|
||||
echo -e " ${YELLOW}${ICON_WARNING}${NC} Google Chrome running · old versions cleanup skipped"
|
||||
return 0
|
||||
fi
|
||||
@@ -182,8 +164,8 @@ clean_edge_old_versions() {
|
||||
"$HOME/Applications/Microsoft Edge.app"
|
||||
)
|
||||
|
||||
# Use -f to match Edge Helper processes as well
|
||||
if pgrep -f "Microsoft Edge" > /dev/null 2>&1; then
|
||||
# Match the exact Edge process name to avoid false positives (e.g., Microsoft Teams)
|
||||
if pgrep -x "Microsoft Edge" > /dev/null 2>&1; then
|
||||
echo -e " ${YELLOW}${ICON_WARNING}${NC} Microsoft Edge running · old versions cleanup skipped"
|
||||
return 0
|
||||
fi
|
||||
@@ -260,7 +242,7 @@ clean_edge_updater_old_versions() {
|
||||
local updater_dir="$HOME/Library/Application Support/Microsoft/EdgeUpdater/apps/msedge-stable"
|
||||
[[ -d "$updater_dir" ]] || return 0
|
||||
|
||||
if pgrep -f "Microsoft Edge" > /dev/null 2>&1; then
|
||||
if pgrep -x "Microsoft Edge" > /dev/null 2>&1; then
|
||||
echo -e " ${YELLOW}${ICON_WARNING}${NC} Microsoft Edge running · updater cleanup skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -420,8 +420,8 @@ readonly DATA_PROTECTED_BUNDLES=(
|
||||
"com.netease.163music" # NetEase Music
|
||||
|
||||
# Web Browsers (protect complex storage like IndexedDB, localStorage)
|
||||
"Firefox" # Firefox Application Support
|
||||
"org.mozilla.*" # Firefox bundle IDs
|
||||
"Firefox" # Firefox Application Support
|
||||
"org.mozilla.*" # Firefox bundle IDs
|
||||
|
||||
# License Management & App Stores
|
||||
"com.paddle.Paddle*" # Paddle (license management)
|
||||
@@ -665,6 +665,7 @@ find_app_files() {
|
||||
"$HOME/Library/HTTPStorages/$bundle_id"
|
||||
"$HOME/Library/Cookies/$bundle_id.binarycookies"
|
||||
"$HOME/Library/LaunchAgents/$bundle_id.plist"
|
||||
"$HOME/Library/LaunchDaemons/$bundle_id.plist"
|
||||
"$HOME/Library/Application Scripts/$bundle_id"
|
||||
"$HOME/Library/Services/$app_name.workflow"
|
||||
"$HOME/Library/QuickLook/$app_name.qlgenerator"
|
||||
@@ -739,11 +740,18 @@ find_app_files() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Launch Agents by name (special handling)
|
||||
if [[ ${#app_name} -gt 3 ]] && [[ -d ~/Library/LaunchAgents ]]; then
|
||||
while IFS= read -r -d '' plist; do
|
||||
files_to_clean+=("$plist")
|
||||
done < <(command find ~/Library/LaunchAgents -maxdepth 1 \( -name "*$app_name*.plist" \) -print0 2> /dev/null)
|
||||
# Launch Agents and Daemons by name (special handling)
|
||||
if [[ ${#app_name} -gt 3 ]]; then
|
||||
if [[ -d ~/Library/LaunchAgents ]]; then
|
||||
while IFS= read -r -d '' plist; do
|
||||
files_to_clean+=("$plist")
|
||||
done < <(command find ~/Library/LaunchAgents -maxdepth 1 \( -name "*$app_name*.plist" \) -print0 2> /dev/null)
|
||||
fi
|
||||
if [[ -d ~/Library/LaunchDaemons ]]; then
|
||||
while IFS= read -r -d '' plist; do
|
||||
files_to_clean+=("$plist")
|
||||
done < <(command find ~/Library/LaunchDaemons -maxdepth 1 \( -name "*$app_name*.plist" \) -print0 2> /dev/null)
|
||||
fi
|
||||
fi
|
||||
|
||||
# Handle specialized toolchains and development environments
|
||||
|
||||
@@ -124,14 +124,14 @@ remove_apps_from_dock() {
|
||||
local changed=false
|
||||
for target in "${targets[@]}"; do
|
||||
local app_path="$target"
|
||||
local app_name
|
||||
app_name=$(basename "$app_path" .app)
|
||||
|
||||
# Normalize path for comparison - realpath might fail if app is already deleted
|
||||
local full_path
|
||||
full_path=$(cd "$(dirname "$app_path")" 2> /dev/null && pwd || echo "")
|
||||
[[ -n "$full_path" ]] && full_path="$full_path/$(basename "$app_path")"
|
||||
|
||||
# URL-encode the path for matching against Dock URLs (spaces -> %20)
|
||||
local encoded_path="${full_path// /%20}"
|
||||
|
||||
# Find the index of the app in persistent-apps
|
||||
local i=0
|
||||
while true; do
|
||||
@@ -141,16 +141,17 @@ remove_apps_from_dock() {
|
||||
|
||||
local url
|
||||
url=$(/usr/libexec/PlistBuddy -c "Print :persistent-apps:$i:tile-data:file-data:_CFURLString" "$plist" 2> /dev/null || echo "")
|
||||
[[ -z "$url" ]] && {
|
||||
((i++))
|
||||
continue
|
||||
}
|
||||
|
||||
# Match by label or by path (parsing the CFURLString which is usually a file:// URL)
|
||||
if [[ "$label" == "$app_name" ]] || [[ "$url" == *"$app_name.app"* ]]; then
|
||||
# Double check path if possible to avoid false positives for similarly named apps
|
||||
if [[ -n "$full_path" && "$url" == *"$full_path"* ]] || [[ "$label" == "$app_name" ]]; then
|
||||
if /usr/libexec/PlistBuddy -c "Delete :persistent-apps:$i" "$plist" 2> /dev/null; then
|
||||
changed=true
|
||||
# After deletion, current index i now points to the next item
|
||||
continue
|
||||
fi
|
||||
# Match by URL-encoded path to handle spaces in app names
|
||||
if [[ -n "$encoded_path" && "$url" == *"$encoded_path"* ]]; then
|
||||
if /usr/libexec/PlistBuddy -c "Delete :persistent-apps:$i" "$plist" 2> /dev/null; then
|
||||
changed=true
|
||||
# After deletion, current index i now points to the next item
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
((i++))
|
||||
|
||||
@@ -864,7 +864,14 @@ paginated_multi_select() {
|
||||
# Backspace filter
|
||||
if [[ "$filter_mode" == "true" && -n "$filter_query" ]]; then
|
||||
filter_query="${filter_query%?}"
|
||||
need_full_redraw=true
|
||||
# Fast footer-only update in filter mode (avoid full redraw)
|
||||
local filter_status="${filter_query:-_}"
|
||||
local footer_row=$((items_per_page + 4))
|
||||
printf "\033[%d;1H\033[2K" "$footer_row" >&2
|
||||
local sep=" ${GRAY}|${NC} "
|
||||
printf "%s" "${GRAY}Search: ${filter_status}${NC}${sep}${GRAY}Delete${NC}${sep}${GRAY}Enter Confirm${NC}${sep}${GRAY}ESC Cancel${NC}" >&2
|
||||
printf "\033[%d;1H\033[2K" "$((footer_row + 1))" >&2
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
CHAR:*)
|
||||
@@ -873,7 +880,14 @@ paginated_multi_select() {
|
||||
# avoid accidental leading spaces
|
||||
if [[ -n "$filter_query" || "$ch" != " " ]]; then
|
||||
filter_query+="$ch"
|
||||
need_full_redraw=true
|
||||
# Fast footer-only update in filter mode (avoid full redraw)
|
||||
local filter_status="${filter_query:-_}"
|
||||
local footer_row=$((items_per_page + 4))
|
||||
printf "\033[%d;1H\033[2K" "$footer_row" >&2
|
||||
local sep=" ${GRAY}|${NC} "
|
||||
printf "%s" "${GRAY}Search: ${filter_status}${NC}${sep}${GRAY}Delete${NC}${sep}${GRAY}Enter Confirm${NC}${sep}${GRAY}ESC Cancel${NC}" >&2
|
||||
printf "\033[%d;1H\033[2K" "$((footer_row + 1))" >&2
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -91,6 +91,40 @@ stop_launch_services() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove macOS Login Items for an app
|
||||
remove_login_item() {
|
||||
local app_name="$1"
|
||||
local bundle_id="$2"
|
||||
|
||||
# Skip if no identifiers provided
|
||||
[[ -z "$app_name" && -z "$bundle_id" ]] && return 0
|
||||
|
||||
# Strip .app suffix if present (login items don't include it)
|
||||
local clean_name="${app_name%.app}"
|
||||
|
||||
# Remove from Login Items using index-based deletion (handles broken items)
|
||||
if [[ -n "$clean_name" ]]; then
|
||||
osascript <<-EOF 2>/dev/null || true
|
||||
tell application "System Events"
|
||||
try
|
||||
set itemCount to count of login items
|
||||
-- Delete in reverse order to avoid index shifting
|
||||
repeat with i from itemCount to 1 by -1
|
||||
try
|
||||
set itemName to name of login item i
|
||||
if itemName is "$clean_name" then
|
||||
delete login item i
|
||||
end if
|
||||
end try
|
||||
end repeat
|
||||
end try
|
||||
end tell
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Remove files (handles symlinks, optional sudo).
|
||||
remove_file_list() {
|
||||
local file_list="$1"
|
||||
@@ -350,6 +384,9 @@ batch_uninstall_applications() {
|
||||
[[ -n "$system_files" ]] && has_system_files="true"
|
||||
stop_launch_services "$bundle_id" "$has_system_files"
|
||||
|
||||
# Remove from Login Items
|
||||
remove_login_item "$app_name" "$bundle_id"
|
||||
|
||||
if ! force_kill_app "$app_name" "$app_path"; then
|
||||
reason="still running"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user