mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 15:04:42 +00:00
test: add checks for uninstallable Apple apps in should_protect_from_uninstall function
This commit is contained in:
@@ -20,20 +20,92 @@ fi
|
||||
# Application Management
|
||||
|
||||
# Critical system components protected from uninstallation
|
||||
# Note: We explicitly list system components instead of using "com.apple.*" wildcard
|
||||
# to allow uninstallation of user-installed Apple apps (Xcode, Final Cut Pro, etc.)
|
||||
readonly SYSTEM_CRITICAL_BUNDLES=(
|
||||
"com.apple.*" # System essentials
|
||||
# Core system applications (in /System/Applications/)
|
||||
"com.apple.finder"
|
||||
"com.apple.dock"
|
||||
"com.apple.Safari"
|
||||
"com.apple.mail"
|
||||
"com.apple.systempreferences"
|
||||
"com.apple.SystemSettings"
|
||||
"com.apple.Settings*"
|
||||
"com.apple.controlcenter*"
|
||||
"com.apple.Spotlight"
|
||||
"com.apple.notificationcenterui"
|
||||
"com.apple.loginwindow"
|
||||
"com.apple.Preview"
|
||||
"com.apple.TextEdit"
|
||||
"com.apple.Notes"
|
||||
"com.apple.reminders"
|
||||
"com.apple.iCal"
|
||||
"com.apple.AddressBook"
|
||||
"com.apple.Photos"
|
||||
"com.apple.AppStore"
|
||||
"com.apple.calculator"
|
||||
"com.apple.Dictionary"
|
||||
"com.apple.ScreenSharing"
|
||||
"com.apple.ActivityMonitor"
|
||||
"com.apple.Console"
|
||||
"com.apple.DiskUtility"
|
||||
"com.apple.KeychainAccess"
|
||||
"com.apple.DigitalColorMeter"
|
||||
"com.apple.grapher"
|
||||
"com.apple.Terminal"
|
||||
"com.apple.ScriptEditor2"
|
||||
"com.apple.VoiceOverUtility"
|
||||
"com.apple.BluetoothFileExchange"
|
||||
"com.apple.print.PrinterProxy"
|
||||
"com.apple.systempreferences*"
|
||||
"com.apple.SystemProfiler"
|
||||
"com.apple.FontBook"
|
||||
"com.apple.ColorSyncUtility"
|
||||
"com.apple.audio.AudioMIDISetup"
|
||||
"com.apple.DirectoryUtility"
|
||||
"com.apple.NetworkUtility"
|
||||
"com.apple.exposelauncher"
|
||||
"com.apple.MigrateAssistant"
|
||||
"com.apple.RAIDUtility"
|
||||
"com.apple.BootCampAssistant"
|
||||
|
||||
# System services and daemons
|
||||
"com.apple.SecurityAgent"
|
||||
"com.apple.CoreServices*"
|
||||
"com.apple.SystemUIServer"
|
||||
"com.apple.backgroundtaskmanagement*"
|
||||
"com.apple.loginitems*"
|
||||
"com.apple.sharedfilelist*"
|
||||
"com.apple.sfl*"
|
||||
"com.apple.coreservices*"
|
||||
"com.apple.metadata*"
|
||||
"com.apple.MobileSoftwareUpdate*"
|
||||
"com.apple.SoftwareUpdate*"
|
||||
"com.apple.installer*"
|
||||
"com.apple.frameworks*"
|
||||
"com.apple.security*"
|
||||
"com.apple.keychain*"
|
||||
"com.apple.trustd*"
|
||||
"com.apple.securityd*"
|
||||
"com.apple.cloudd*"
|
||||
"com.apple.iCloud*"
|
||||
"com.apple.WiFi*"
|
||||
"com.apple.airport*"
|
||||
"com.apple.Bluetooth*"
|
||||
|
||||
# Input methods (system built-in)
|
||||
"com.apple.inputmethod.*"
|
||||
"com.apple.inputsource*"
|
||||
"com.apple.TextInput*"
|
||||
"com.apple.CharacterPicker*"
|
||||
"com.apple.PressAndHold*"
|
||||
|
||||
# Legacy pattern-based entries (non com.apple.*)
|
||||
"loginwindow"
|
||||
"dock"
|
||||
"systempreferences"
|
||||
"finder"
|
||||
"safari"
|
||||
"com.apple.Settings*"
|
||||
"com.apple.SystemSettings*"
|
||||
"com.apple.controlcenter*"
|
||||
"com.apple.backgroundtaskmanagement*"
|
||||
"com.apple.loginitems*"
|
||||
"com.apple.sharedfilelist*"
|
||||
"com.apple.sfl*"
|
||||
"backgroundtaskmanagementagent"
|
||||
"keychain*"
|
||||
"security*"
|
||||
@@ -55,11 +127,22 @@ readonly SYSTEM_CRITICAL_BUNDLES=(
|
||||
"KeyLayout*"
|
||||
"GlobalPreferences"
|
||||
".GlobalPreferences"
|
||||
"com.apple.inputmethod.*"
|
||||
"org.pqrs.Karabiner*"
|
||||
"com.apple.inputsource*"
|
||||
"com.apple.TextInputMenuAgent"
|
||||
"com.apple.TextInputSwitcher"
|
||||
)
|
||||
|
||||
# Apple apps that CAN be uninstalled (from App Store or developer.apple.com)
|
||||
readonly APPLE_UNINSTALLABLE_APPS=(
|
||||
"com.apple.dt.*" # Xcode, Instruments, FileMerge
|
||||
"com.apple.FinalCut*" # Final Cut Pro
|
||||
"com.apple.Motion"
|
||||
"com.apple.Compressor"
|
||||
"com.apple.logic*" # Logic Pro
|
||||
"com.apple.garageband*" # GarageBand
|
||||
"com.apple.iMovie"
|
||||
"com.apple.iWork.*" # Pages, Numbers, Keynote
|
||||
"com.apple.MainStage*"
|
||||
"com.apple.server.*" # macOS Server
|
||||
"com.apple.Playgrounds" # Swift Playgrounds
|
||||
)
|
||||
|
||||
# Applications with sensitive data; protected during cleanup but removable
|
||||
@@ -74,360 +157,355 @@ readonly DATA_PROTECTED_BUNDLES=(
|
||||
"*.InputMethod"
|
||||
"*IME"
|
||||
|
||||
# System Utilities & Cleanup Tools
|
||||
"com.nektony.*" # App Cleaner & Uninstaller
|
||||
"com.macpaw.*" # CleanMyMac, CleanMaster
|
||||
"com.freemacsoft.AppCleaner" # AppCleaner
|
||||
"com.omnigroup.omnidisksweeper" # OmniDiskSweeper
|
||||
"com.daisydiskapp.*" # DaisyDisk
|
||||
"com.tunabellysoftware.*" # Disk Utility apps
|
||||
"com.grandperspectiv.*" # GrandPerspective
|
||||
"com.binaryfruit.*" # FusionCast
|
||||
# System Utilities & Cleanup
|
||||
"com.nektony.*"
|
||||
"com.macpaw.*"
|
||||
"com.freemacsoft.AppCleaner"
|
||||
"com.omnigroup.omnidisksweeper"
|
||||
"com.daisydiskapp.*"
|
||||
"com.tunabellysoftware.*"
|
||||
"com.grandperspectiv.*"
|
||||
"com.binaryfruit.*"
|
||||
|
||||
# Password Managers & Security
|
||||
"com.1password.*" # 1Password
|
||||
"com.agilebits.*" # 1Password legacy
|
||||
"com.lastpass.*" # LastPass
|
||||
"com.dashlane.*" # Dashlane
|
||||
"com.bitwarden.*" # Bitwarden
|
||||
"com.keepassx.*" # KeePassXC (Legacy)
|
||||
"org.keepassx.*" # KeePassX
|
||||
"org.keepassxc.*" # KeePassXC
|
||||
"com.authy.*" # Authy
|
||||
"com.yubico.*" # YubiKey Manager
|
||||
# Password Managers
|
||||
"com.1password.*"
|
||||
"com.agilebits.*"
|
||||
"com.lastpass.*"
|
||||
"com.dashlane.*"
|
||||
"com.bitwarden.*"
|
||||
"com.keepassx.*"
|
||||
"org.keepassx.*"
|
||||
"org.keepassxc.*"
|
||||
"com.authy.*"
|
||||
"com.yubico.*"
|
||||
|
||||
# Development Tools - IDEs & Editors
|
||||
"com.jetbrains.*" # JetBrains IDEs (IntelliJ, DataGrip, etc.)
|
||||
"JetBrains*" # JetBrains Application Support folders
|
||||
"com.microsoft.VSCode" # Visual Studio Code
|
||||
"com.visualstudio.code.*" # VS Code variants
|
||||
"com.sublimetext.*" # Sublime Text
|
||||
"com.sublimehq.*" # Sublime Merge
|
||||
"com.microsoft.VSCodeInsiders" # VS Code Insiders
|
||||
"com.apple.dt.Xcode" # Xcode (keep settings)
|
||||
"com.coteditor.CotEditor" # CotEditor
|
||||
"com.macromates.TextMate" # TextMate
|
||||
"com.panic.Nova" # Nova
|
||||
"abnerworks.Typora" # Typora (Markdown editor)
|
||||
"com.uranusjr.macdown" # MacDown
|
||||
# IDEs & Editors
|
||||
"com.jetbrains.*"
|
||||
"JetBrains*"
|
||||
"com.microsoft.VSCode"
|
||||
"com.visualstudio.code.*"
|
||||
"com.sublimetext.*"
|
||||
"com.sublimehq.*"
|
||||
"com.microsoft.VSCodeInsiders"
|
||||
"com.apple.dt.Xcode"
|
||||
"com.coteditor.CotEditor"
|
||||
"com.macromates.TextMate"
|
||||
"com.panic.Nova"
|
||||
"abnerworks.Typora"
|
||||
"com.uranusjr.macdown"
|
||||
|
||||
# AI & LLM Tools
|
||||
"com.todesktop.*" # Cursor (often uses generic todesktop ID)
|
||||
"Cursor" # Cursor App Support
|
||||
"com.anthropic.claude*" # Claude
|
||||
"Claude" # Claude App Support
|
||||
"com.openai.chat*" # ChatGPT
|
||||
"ChatGPT" # ChatGPT App Support
|
||||
"com.ollama.ollama" # Ollama
|
||||
"Ollama" # Ollama App Support
|
||||
"com.lmstudio.lmstudio" # LM Studio
|
||||
"LM Studio" # LM Studio App Support
|
||||
"co.supertool.chatbox" # Chatbox
|
||||
"page.jan.jan" # Jan
|
||||
"com.huggingface.huggingchat" # HuggingChat
|
||||
"Gemini" # Gemini
|
||||
"com.perplexity.Perplexity" # Perplexity
|
||||
"com.drawthings.DrawThings" # Draw Things
|
||||
"com.divamgupta.diffusionbee" # DiffusionBee
|
||||
"com.exafunction.windsurf" # Windsurf
|
||||
"com.quora.poe.electron" # Poe
|
||||
"chat.openai.com.*" # OpenAI web wrappers
|
||||
"com.todesktop.*"
|
||||
"Cursor"
|
||||
"com.anthropic.claude*"
|
||||
"Claude"
|
||||
"com.openai.chat*"
|
||||
"ChatGPT"
|
||||
"com.ollama.ollama"
|
||||
"Ollama"
|
||||
"com.lmstudio.lmstudio"
|
||||
"LM Studio"
|
||||
"co.supertool.chatbox"
|
||||
"page.jan.jan"
|
||||
"com.huggingface.huggingchat"
|
||||
"Gemini"
|
||||
"com.perplexity.Perplexity"
|
||||
"com.drawthings.DrawThings"
|
||||
"com.divamgupta.diffusionbee"
|
||||
"com.exafunction.windsurf"
|
||||
"com.quora.poe.electron"
|
||||
"chat.openai.com.*"
|
||||
|
||||
# Development Tools - Database Clients
|
||||
"com.sequelpro.*" # Sequel Pro
|
||||
"com.sequel-ace.*" # Sequel Ace
|
||||
"com.tinyapp.*" # TablePlus
|
||||
"com.dbeaver.*" # DBeaver
|
||||
"com.navicat.*" # Navicat
|
||||
"com.mongodb.compass" # MongoDB Compass
|
||||
"com.redis.RedisInsight" # Redis Insight
|
||||
"com.pgadmin.pgadmin4" # pgAdmin
|
||||
"com.eggerapps.Sequel-Pro" # Sequel Pro legacy
|
||||
"com.valentina-db.Valentina-Studio" # Valentina Studio
|
||||
"com.dbvis.DbVisualizer" # DbVisualizer
|
||||
# Database Clients
|
||||
"com.sequelpro.*"
|
||||
"com.sequel-ace.*"
|
||||
"com.tinyapp.*"
|
||||
"com.dbeaver.*"
|
||||
"com.navicat.*"
|
||||
"com.mongodb.compass"
|
||||
"com.redis.RedisInsight"
|
||||
"com.pgadmin.pgadmin4"
|
||||
"com.eggerapps.Sequel-Pro"
|
||||
"com.valentina-db.Valentina-Studio"
|
||||
"com.dbvis.DbVisualizer"
|
||||
|
||||
# Development Tools - API & Network
|
||||
"com.postmanlabs.mac" # Postman
|
||||
"com.konghq.insomnia" # Insomnia
|
||||
"com.CharlesProxy.*" # Charles Proxy
|
||||
"com.proxyman.*" # Proxyman
|
||||
"com.getpaw.*" # Paw
|
||||
"com.luckymarmot.Paw" # Paw legacy
|
||||
"com.charlesproxy.charles" # Charles
|
||||
"com.telerik.Fiddler" # Fiddler
|
||||
"com.usebruno.app" # Bruno (API client)
|
||||
# API & Network Tools
|
||||
"com.postmanlabs.mac"
|
||||
"com.konghq.insomnia"
|
||||
"com.CharlesProxy.*"
|
||||
"com.proxyman.*"
|
||||
"com.getpaw.*"
|
||||
"com.luckymarmot.Paw"
|
||||
"com.charlesproxy.charles"
|
||||
"com.telerik.Fiddler"
|
||||
"com.usebruno.app"
|
||||
|
||||
# Network Proxy & VPN Tools (pattern-based protection)
|
||||
# Clash variants
|
||||
"*clash*" # All Clash variants (ClashX, ClashX Pro, Clash Verge, etc)
|
||||
"*Clash*" # Capitalized variants
|
||||
"com.nssurge.surge-mac" # Surge
|
||||
"*surge*" # Surge variants
|
||||
"*Surge*" # Surge variants
|
||||
"mihomo*" # Mihomo Party and variants
|
||||
"*openvpn*" # OpenVPN Connect and variants
|
||||
"*OpenVPN*" # OpenVPN capitalized variants
|
||||
"net.openvpn.*" # OpenVPN bundle IDs
|
||||
# Network Proxy & VPN Tools
|
||||
"*clash*"
|
||||
"*Clash*"
|
||||
"com.nssurge.surge-mac"
|
||||
"*surge*"
|
||||
"*Surge*"
|
||||
"mihomo*"
|
||||
"*openvpn*"
|
||||
"*OpenVPN*"
|
||||
"net.openvpn.*"
|
||||
|
||||
# Proxy Clients (Shadowsocks, V2Ray, etc)
|
||||
"*ShadowsocksX-NG*" # ShadowsocksX-NG
|
||||
"com.qiuyuzhou.*" # ShadowsocksX-NG bundle
|
||||
"*v2ray*" # V2Ray variants
|
||||
"*V2Ray*" # V2Ray variants
|
||||
"*v2box*" # V2Box
|
||||
"*V2Box*" # V2Box
|
||||
"*nekoray*" # Nekoray
|
||||
"*sing-box*" # Sing-box
|
||||
"*OneBox*" # OneBox
|
||||
"*hiddify*" # Hiddify
|
||||
"*Hiddify*" # Hiddify
|
||||
"*loon*" # Loon
|
||||
"*Loon*" # Loon
|
||||
"*quantumult*" # Quantumult X
|
||||
# Proxy Clients
|
||||
"*ShadowsocksX-NG*"
|
||||
"com.qiuyuzhou.*"
|
||||
"*v2ray*"
|
||||
"*V2Ray*"
|
||||
"*v2box*"
|
||||
"*V2Box*"
|
||||
"*nekoray*"
|
||||
"*sing-box*"
|
||||
"*OneBox*"
|
||||
"*hiddify*"
|
||||
"*Hiddify*"
|
||||
"*loon*"
|
||||
"*Loon*"
|
||||
"*quantumult*"
|
||||
|
||||
# Mesh & Corporate VPNs
|
||||
"*tailscale*" # Tailscale
|
||||
"io.tailscale.*" # Tailscale bundle
|
||||
"*zerotier*" # ZeroTier
|
||||
"com.zerotier.*" # ZeroTier bundle
|
||||
"*1dot1dot1dot1*" # Cloudflare WARP
|
||||
"*cloudflare*warp*" # Cloudflare WARP
|
||||
"*tailscale*"
|
||||
"io.tailscale.*"
|
||||
"*zerotier*"
|
||||
"com.zerotier.*"
|
||||
"*1dot1dot1dot1*" # Cloudflare WARP
|
||||
"*cloudflare*warp*"
|
||||
|
||||
# Commercial VPNs
|
||||
"*nordvpn*" # NordVPN
|
||||
"*expressvpn*" # ExpressVPN
|
||||
"*protonvpn*" # ProtonVPN
|
||||
"*surfshark*" # Surfshark
|
||||
"*windscribe*" # Windscribe
|
||||
"*mullvad*" # Mullvad
|
||||
"*privateinternetaccess*" # PIA
|
||||
"*nordvpn*"
|
||||
"*expressvpn*"
|
||||
"*protonvpn*"
|
||||
"*surfshark*"
|
||||
"*windscribe*"
|
||||
"*mullvad*"
|
||||
"*privateinternetaccess*"
|
||||
|
||||
# Screensaver & Dynamic Wallpaper
|
||||
"*Aerial*" # Aerial screensaver (all case variants)
|
||||
"*aerial*" # Aerial lowercase
|
||||
"*Fliqlo*" # Fliqlo screensaver (all case variants)
|
||||
"*fliqlo*" # Fliqlo lowercase
|
||||
# Screensaver & Wallpaper
|
||||
"*Aerial*"
|
||||
"*aerial*"
|
||||
"*Fliqlo*"
|
||||
"*fliqlo*"
|
||||
|
||||
# Development Tools - Git & Version Control
|
||||
"com.github.GitHubDesktop" # GitHub Desktop
|
||||
"com.sublimemerge" # Sublime Merge
|
||||
"com.torusknot.SourceTreeNotMAS" # SourceTree
|
||||
"com.git-tower.Tower*" # Tower
|
||||
"com.gitfox.GitFox" # GitFox
|
||||
"com.github.Gitify" # Gitify
|
||||
"com.fork.Fork" # Fork
|
||||
"com.axosoft.gitkraken" # GitKraken
|
||||
# Git & Version Control
|
||||
"com.github.GitHubDesktop"
|
||||
"com.sublimemerge"
|
||||
"com.torusknot.SourceTreeNotMAS"
|
||||
"com.git-tower.Tower*"
|
||||
"com.gitfox.GitFox"
|
||||
"com.github.Gitify"
|
||||
"com.fork.Fork"
|
||||
"com.axosoft.gitkraken"
|
||||
|
||||
# Development Tools - Terminal & Shell
|
||||
"com.googlecode.iterm2" # iTerm2
|
||||
"net.kovidgoyal.kitty" # Kitty
|
||||
"io.alacritty" # Alacritty
|
||||
"com.github.wez.wezterm" # WezTerm
|
||||
"com.hyper.Hyper" # Hyper
|
||||
"com.mizage.divvy" # Divvy
|
||||
"com.fig.Fig" # Fig (terminal assistant)
|
||||
"dev.warp.Warp-Stable" # Warp
|
||||
"com.termius-dmg" # Termius (SSH client)
|
||||
# Terminal & Shell
|
||||
"com.googlecode.iterm2"
|
||||
"net.kovidgoyal.kitty"
|
||||
"io.alacritty"
|
||||
"com.github.wez.wezterm"
|
||||
"com.hyper.Hyper"
|
||||
"com.mizage.divvy"
|
||||
"com.fig.Fig"
|
||||
"dev.warp.Warp-Stable"
|
||||
"com.termius-dmg"
|
||||
|
||||
# Development Tools - Docker & Virtualization
|
||||
"com.docker.docker" # Docker Desktop
|
||||
"com.getutm.UTM" # UTM
|
||||
"com.vmware.fusion" # VMware Fusion
|
||||
"com.parallels.desktop.*" # Parallels Desktop
|
||||
"org.virtualbox.app.VirtualBox" # VirtualBox
|
||||
"com.vagrant.*" # Vagrant
|
||||
"com.orbstack.OrbStack" # OrbStack
|
||||
# Docker & Virtualization
|
||||
"com.docker.docker"
|
||||
"com.getutm.UTM"
|
||||
"com.vmware.fusion"
|
||||
"com.parallels.desktop.*"
|
||||
"org.virtualbox.app.VirtualBox"
|
||||
"com.vagrant.*"
|
||||
"com.orbstack.OrbStack"
|
||||
|
||||
# System Monitoring & Performance
|
||||
"com.bjango.istatmenus*" # iStat Menus
|
||||
"eu.exelban.Stats" # Stats
|
||||
"com.monitorcontrol.*" # MonitorControl
|
||||
"com.bresink.system-toolkit.*" # TinkerTool System
|
||||
"com.mediaatelier.MenuMeters" # MenuMeters
|
||||
"com.activity-indicator.app" # Activity Indicator
|
||||
"net.cindori.sensei" # Sensei
|
||||
# System Monitoring
|
||||
"com.bjango.istatmenus*"
|
||||
"eu.exelban.Stats"
|
||||
"com.monitorcontrol.*"
|
||||
"com.bresink.system-toolkit.*"
|
||||
"com.mediaatelier.MenuMeters"
|
||||
"com.activity-indicator.app"
|
||||
"net.cindori.sensei"
|
||||
|
||||
# Window Management & Productivity
|
||||
"com.macitbetter.*" # BetterTouchTool, BetterSnapTool
|
||||
"com.hegenberg.*" # BetterTouchTool legacy
|
||||
"com.manytricks.*" # Moom, Witch, Name Mangler, Resolutionator
|
||||
"com.divisiblebyzero.*" # Spectacle
|
||||
"com.koingdev.*" # Koingg apps
|
||||
"com.if.Amphetamine" # Amphetamine
|
||||
"com.lwouis.alt-tab-macos" # AltTab
|
||||
"net.matthewpalmer.Vanilla" # Vanilla
|
||||
"com.lightheadsw.Caffeine" # Caffeine
|
||||
"com.contextual.Contexts" # Contexts
|
||||
"com.amethyst.Amethyst" # Amethyst
|
||||
"com.knollsoft.Rectangle" # Rectangle
|
||||
"com.knollsoft.Hookshot" # Hookshot
|
||||
"com.surteesstudios.Bartender" # Bartender
|
||||
"com.gaosun.eul" # eul (system monitor)
|
||||
"com.pointum.hazeover" # HazeOver
|
||||
# Window Management
|
||||
"com.macitbetter.*" # BetterTouchTool, BetterSnapTool
|
||||
"com.hegenberg.*"
|
||||
"com.manytricks.*" # Moom, Witch, etc.
|
||||
"com.divisiblebyzero.*"
|
||||
"com.koingdev.*"
|
||||
"com.if.Amphetamine"
|
||||
"com.lwouis.alt-tab-macos"
|
||||
"net.matthewpalmer.Vanilla"
|
||||
"com.lightheadsw.Caffeine"
|
||||
"com.contextual.Contexts"
|
||||
"com.amethyst.Amethyst"
|
||||
"com.knollsoft.Rectangle"
|
||||
"com.knollsoft.Hookshot"
|
||||
"com.surteesstudios.Bartender"
|
||||
"com.gaosun.eul"
|
||||
"com.pointum.hazeover"
|
||||
|
||||
# Launcher & Automation
|
||||
"com.runningwithcrayons.Alfred" # Alfred
|
||||
"com.raycast.macos" # Raycast
|
||||
"com.blacktree.Quicksilver" # Quicksilver
|
||||
"com.stairways.keyboardmaestro.*" # Keyboard Maestro
|
||||
"com.manytricks.Butler" # Butler
|
||||
"com.happenapps.Quitter" # Quitter
|
||||
"com.pilotmoon.scroll-reverser" # Scroll Reverser
|
||||
"org.pqrs.Karabiner-Elements" # Karabiner-Elements
|
||||
"com.apple.Automator" # Automator (system, but keep user workflows)
|
||||
"com.runningwithcrayons.Alfred"
|
||||
"com.raycast.macos"
|
||||
"com.blacktree.Quicksilver"
|
||||
"com.stairways.keyboardmaestro.*"
|
||||
"com.manytricks.Butler"
|
||||
"com.happenapps.Quitter"
|
||||
"com.pilotmoon.scroll-reverser"
|
||||
"org.pqrs.Karabiner-Elements"
|
||||
"com.apple.Automator"
|
||||
|
||||
# Note-Taking & Documentation
|
||||
"com.bear-writer.*" # Bear
|
||||
"com.typora.*" # Typora
|
||||
"com.ulyssesapp.*" # Ulysses
|
||||
"com.literatureandlatte.*" # Scrivener
|
||||
"com.dayoneapp.*" # Day One
|
||||
"notion.id" # Notion
|
||||
"md.obsidian" # Obsidian
|
||||
"com.logseq.logseq" # Logseq
|
||||
"com.evernote.Evernote" # Evernote
|
||||
"com.onenote.mac" # OneNote
|
||||
"com.omnigroup.OmniOutliner*" # OmniOutliner
|
||||
"net.shinyfrog.bear" # Bear legacy
|
||||
"com.goodnotes.GoodNotes" # GoodNotes
|
||||
"com.marginnote.MarginNote*" # MarginNote
|
||||
"com.roamresearch.*" # Roam Research
|
||||
"com.reflect.ReflectApp" # Reflect
|
||||
"com.inkdrop.*" # Inkdrop
|
||||
# Note-Taking
|
||||
"com.bear-writer.*"
|
||||
"com.typora.*"
|
||||
"com.ulyssesapp.*"
|
||||
"com.literatureandlatte.*"
|
||||
"com.dayoneapp.*"
|
||||
"notion.id"
|
||||
"md.obsidian"
|
||||
"com.logseq.logseq"
|
||||
"com.evernote.Evernote"
|
||||
"com.onenote.mac"
|
||||
"com.omnigroup.OmniOutliner*"
|
||||
"net.shinyfrog.bear"
|
||||
"com.goodnotes.GoodNotes"
|
||||
"com.marginnote.MarginNote*"
|
||||
"com.roamresearch.*"
|
||||
"com.reflect.ReflectApp"
|
||||
"com.inkdrop.*"
|
||||
|
||||
# Design & Creative Tools
|
||||
"com.adobe.*" # Adobe Creative Suite
|
||||
"com.bohemiancoding.*" # Sketch
|
||||
"com.figma.*" # Figma
|
||||
"com.framerx.*" # Framer
|
||||
"com.zeplin.*" # Zeplin
|
||||
"com.invisionapp.*" # InVision
|
||||
"com.principle.*" # Principle
|
||||
"com.pixelmatorteam.*" # Pixelmator
|
||||
"com.affinitydesigner.*" # Affinity Designer
|
||||
"com.affinityphoto.*" # Affinity Photo
|
||||
"com.affinitypublisher.*" # Affinity Publisher
|
||||
"com.linearity.curve" # Linearity Curve
|
||||
"com.canva.CanvaDesktop" # Canva
|
||||
"com.maxon.cinema4d" # Cinema 4D
|
||||
"com.autodesk.*" # Autodesk products
|
||||
"com.sketchup.*" # SketchUp
|
||||
# Design & Creative
|
||||
"com.adobe.*"
|
||||
"com.bohemiancoding.*"
|
||||
"com.figma.*"
|
||||
"com.framerx.*"
|
||||
"com.zeplin.*"
|
||||
"com.invisionapp.*"
|
||||
"com.principle.*"
|
||||
"com.pixelmatorteam.*"
|
||||
"com.affinitydesigner.*"
|
||||
"com.affinityphoto.*"
|
||||
"com.affinitypublisher.*"
|
||||
"com.linearity.curve"
|
||||
"com.canva.CanvaDesktop"
|
||||
"com.maxon.cinema4d"
|
||||
"com.autodesk.*"
|
||||
"com.sketchup.*"
|
||||
|
||||
# Communication & Collaboration
|
||||
"com.tencent.xinWeChat" # WeChat (Chinese users)
|
||||
"com.tencent.qq" # QQ
|
||||
"com.alibaba.DingTalkMac" # DingTalk
|
||||
"com.alibaba.AliLang.osx" # AliLang (retain login/config data)
|
||||
"com.alibaba.alilang3.osx.ShipIt" # AliLang updater component
|
||||
"com.alibaba.AlilangMgr.QueryNetworkInfo" # AliLang network helper
|
||||
"us.zoom.xos" # Zoom
|
||||
"com.microsoft.teams*" # Microsoft Teams
|
||||
"com.slack.Slack" # Slack
|
||||
"com.hnc.Discord" # Discord
|
||||
"app.legcord.Legcord" # Legcord
|
||||
"org.telegram.desktop" # Telegram
|
||||
"ru.keepcoder.Telegram" # Telegram legacy
|
||||
"net.whatsapp.WhatsApp" # WhatsApp
|
||||
"com.skype.skype" # Skype
|
||||
"com.cisco.webexmeetings" # Webex
|
||||
"com.ringcentral.RingCentral" # RingCentral
|
||||
"com.readdle.smartemail-Mac" # Spark Email
|
||||
"com.airmail.*" # Airmail
|
||||
"com.postbox-inc.postbox" # Postbox
|
||||
"com.tinyspeck.slackmacgap" # Slack legacy
|
||||
# Communication
|
||||
"com.tencent.xinWeChat"
|
||||
"com.tencent.qq"
|
||||
"com.alibaba.DingTalkMac"
|
||||
"com.alibaba.AliLang.osx"
|
||||
"com.alibaba.alilang3.osx.ShipIt"
|
||||
"com.alibaba.AlilangMgr.QueryNetworkInfo"
|
||||
"us.zoom.xos"
|
||||
"com.microsoft.teams*"
|
||||
"com.slack.Slack"
|
||||
"com.hnc.Discord"
|
||||
"app.legcord.Legcord"
|
||||
"org.telegram.desktop"
|
||||
"ru.keepcoder.Telegram"
|
||||
"net.whatsapp.WhatsApp"
|
||||
"com.skype.skype"
|
||||
"com.cisco.webexmeetings"
|
||||
"com.ringcentral.RingCentral"
|
||||
"com.readdle.smartemail-Mac"
|
||||
"com.airmail.*"
|
||||
"com.postbox-inc.postbox"
|
||||
"com.tinyspeck.slackmacgap"
|
||||
|
||||
# Task Management & Productivity
|
||||
"com.omnigroup.OmniFocus*" # OmniFocus
|
||||
"com.culturedcode.*" # Things
|
||||
"com.todoist.*" # Todoist
|
||||
"com.any.do.*" # Any.do
|
||||
"com.ticktick.*" # TickTick
|
||||
"com.microsoft.to-do" # Microsoft To Do
|
||||
"com.trello.trello" # Trello
|
||||
"com.asana.nativeapp" # Asana
|
||||
"com.clickup.*" # ClickUp
|
||||
"com.monday.desktop" # Monday.com
|
||||
"com.airtable.airtable" # Airtable
|
||||
"com.notion.id" # Notion (also note-taking)
|
||||
"com.linear.linear" # Linear
|
||||
# Task Management
|
||||
"com.omnigroup.OmniFocus*"
|
||||
"com.culturedcode.*"
|
||||
"com.todoist.*"
|
||||
"com.any.do.*"
|
||||
"com.ticktick.*"
|
||||
"com.microsoft.to-do"
|
||||
"com.trello.trello"
|
||||
"com.asana.nativeapp"
|
||||
"com.clickup.*"
|
||||
"com.monday.desktop"
|
||||
"com.airtable.airtable"
|
||||
"com.notion.id"
|
||||
"com.linear.linear"
|
||||
|
||||
# File Transfer & Sync
|
||||
"com.panic.transmit*" # Transmit (FTP/SFTP)
|
||||
"com.binarynights.ForkLift*" # ForkLift
|
||||
"com.noodlesoft.Hazel" # Hazel
|
||||
"com.cyberduck.Cyberduck" # Cyberduck
|
||||
"io.filezilla.FileZilla" # FileZilla
|
||||
"com.apple.Xcode.CloudDocuments" # Xcode Cloud Documents
|
||||
"com.synology.*" # Synology apps
|
||||
"com.panic.transmit*"
|
||||
"com.binarynights.ForkLift*"
|
||||
"com.noodlesoft.Hazel"
|
||||
"com.cyberduck.Cyberduck"
|
||||
"io.filezilla.FileZilla"
|
||||
"com.apple.Xcode.CloudDocuments"
|
||||
"com.synology.*"
|
||||
|
||||
# Cloud Storage & Backup (Issue #204)
|
||||
"com.dropbox.*" # Dropbox
|
||||
"com.getdropbox.*" # Dropbox legacy
|
||||
"*dropbox*" # Dropbox helpers/updaters
|
||||
"ws.agile.*" # 1Password sync helpers
|
||||
"com.backblaze.*" # Backblaze
|
||||
"*backblaze*" # Backblaze helpers
|
||||
"com.box.desktop*" # Box
|
||||
"*box.desktop*" # Box helpers
|
||||
"com.microsoft.OneDrive*" # Microsoft OneDrive
|
||||
"com.microsoft.SyncReporter" # OneDrive sync reporter
|
||||
"*OneDrive*" # OneDrive helpers/updaters
|
||||
"com.google.GoogleDrive" # Google Drive
|
||||
"com.google.keystone*" # Google updaters (Drive, Chrome, etc.)
|
||||
"*GoogleDrive*" # Google Drive helpers
|
||||
"com.amazon.drive" # Amazon Drive
|
||||
"com.apple.bird" # iCloud Drive daemon
|
||||
"com.apple.CloudDocs*" # iCloud Documents
|
||||
"com.displaylink.*" # DisplayLink
|
||||
"com.fujitsu.pfu.ScanSnap*" # ScanSnap
|
||||
"com.citrix.*" # Citrix Workspace
|
||||
"org.xquartz.*" # XQuartz
|
||||
"us.zoom.updater*" # Zoom updaters
|
||||
"com.DigiDNA.iMazing*" # iMazing
|
||||
"com.shirtpocket.*" # SuperDuper backup
|
||||
"homebrew.mxcl.*" # Homebrew services
|
||||
# Cloud Storage & Backup
|
||||
"com.dropbox.*"
|
||||
"com.getdropbox.*"
|
||||
"*dropbox*"
|
||||
"ws.agile.*"
|
||||
"com.backblaze.*"
|
||||
"*backblaze*"
|
||||
"com.box.desktop*"
|
||||
"*box.desktop*"
|
||||
"com.microsoft.OneDrive*"
|
||||
"com.microsoft.SyncReporter"
|
||||
"*OneDrive*"
|
||||
"com.google.GoogleDrive"
|
||||
"com.google.keystone*"
|
||||
"*GoogleDrive*"
|
||||
"com.amazon.drive"
|
||||
"com.apple.bird"
|
||||
"com.apple.CloudDocs*"
|
||||
"com.displaylink.*"
|
||||
"com.fujitsu.pfu.ScanSnap*"
|
||||
"com.citrix.*"
|
||||
"org.xquartz.*"
|
||||
"us.zoom.updater*"
|
||||
"com.DigiDNA.iMazing*"
|
||||
"com.shirtpocket.*"
|
||||
"homebrew.mxcl.*"
|
||||
|
||||
# Screenshot & Recording
|
||||
"com.cleanshot.*" # CleanShot X
|
||||
"com.xnipapp.xnip" # Xnip
|
||||
"com.reincubate.camo" # Camo
|
||||
"com.tunabellysoftware.ScreenFloat" # ScreenFloat
|
||||
"net.telestream.screenflow*" # ScreenFlow
|
||||
"com.techsmith.snagit*" # Snagit
|
||||
"com.techsmith.camtasia*" # Camtasia
|
||||
"com.obsidianapp.screenrecorder" # Screen Recorder
|
||||
"com.kap.Kap" # Kap
|
||||
"com.getkap.*" # Kap legacy
|
||||
"com.linebreak.CloudApp" # CloudApp
|
||||
"com.droplr.droplr-mac" # Droplr
|
||||
"com.cleanshot.*"
|
||||
"com.xnipapp.xnip"
|
||||
"com.reincubate.camo"
|
||||
"com.tunabellysoftware.ScreenFloat"
|
||||
"net.telestream.screenflow*"
|
||||
"com.techsmith.snagit*"
|
||||
"com.techsmith.camtasia*"
|
||||
"com.obsidianapp.screenrecorder"
|
||||
"com.kap.Kap"
|
||||
"com.getkap.*"
|
||||
"com.linebreak.CloudApp"
|
||||
"com.droplr.droplr-mac"
|
||||
|
||||
# Media & Entertainment
|
||||
"com.spotify.client" # Spotify
|
||||
"com.apple.Music" # Apple Music
|
||||
"com.apple.podcasts" # Apple Podcasts
|
||||
"com.apple.BKAgentService" # Apple Books (Agent)
|
||||
"com.apple.iBooksX" # Apple Books
|
||||
"com.apple.iBooks" # Apple Books (Legacy)
|
||||
"com.apple.FinalCutPro" # Final Cut Pro
|
||||
"com.apple.Motion" # Motion
|
||||
"com.apple.Compressor" # Compressor
|
||||
"com.blackmagic-design.*" # DaVinci Resolve
|
||||
"com.colliderli.iina" # IINA
|
||||
"org.videolan.vlc" # VLC
|
||||
"io.mpv" # MPV
|
||||
"com.noodlesoft.Hazel" # Hazel (automation)
|
||||
"tv.plex.player.desktop" # Plex
|
||||
"com.netease.163music" # NetEase Music
|
||||
"com.spotify.client"
|
||||
"com.apple.Music"
|
||||
"com.apple.podcasts"
|
||||
"com.apple.BKAgentService"
|
||||
"com.apple.iBooksX"
|
||||
"com.apple.iBooks"
|
||||
"com.blackmagic-design.*"
|
||||
"com.colliderli.iina"
|
||||
"org.videolan.vlc"
|
||||
"io.mpv"
|
||||
"tv.plex.player.desktop"
|
||||
"com.netease.163music"
|
||||
|
||||
# Web Browsers (protect complex storage like IndexedDB, localStorage)
|
||||
"Firefox" # Firefox Application Support
|
||||
"org.mozilla.*" # Firefox bundle IDs
|
||||
# Web Browsers
|
||||
"Firefox"
|
||||
"org.mozilla.*"
|
||||
|
||||
# License Management & App Stores
|
||||
"com.paddle.Paddle*" # Paddle (license management)
|
||||
"com.setapp.DesktopClient" # Setapp
|
||||
"com.devmate.*" # DevMate (license framework)
|
||||
"org.sparkle-project.Sparkle" # Sparkle (update framework)
|
||||
# License & App Stores
|
||||
"com.paddle.Paddle*"
|
||||
"com.setapp.DesktopClient"
|
||||
"com.devmate.*"
|
||||
"org.sparkle-project.Sparkle"
|
||||
)
|
||||
|
||||
# Centralized check for critical system components (case-insensitive)
|
||||
@@ -470,11 +548,22 @@ bundle_matches_pattern() {
|
||||
# Check if application is a protected system component
|
||||
should_protect_from_uninstall() {
|
||||
local bundle_id="$1"
|
||||
for pattern in "${SYSTEM_CRITICAL_BUNDLES[@]}"; do
|
||||
|
||||
# First check if it's an uninstallable Apple app
|
||||
# These apps have com.apple.* bundle IDs but are NOT system-critical
|
||||
for pattern in "${APPLE_UNINSTALLABLE_APPS[@]}"; do
|
||||
if bundle_matches_pattern "$bundle_id" "$pattern"; then
|
||||
return 0
|
||||
return 1 # Can be uninstalled
|
||||
fi
|
||||
done
|
||||
|
||||
# Then check system-critical components
|
||||
for pattern in "${SYSTEM_CRITICAL_BUNDLES[@]}"; do
|
||||
if bundle_matches_pattern "$bundle_id" "$pattern"; then
|
||||
return 0 # Protected
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -582,7 +671,13 @@ should_protect_path() {
|
||||
# This catches things like /Users/tw93/Library/Caches/Claude when pattern is *Claude*
|
||||
# In uninstall mode, only check system-critical bundles (user explicitly chose to uninstall)
|
||||
if [[ "${MOLE_UNINSTALL_MODE:-0}" == "1" ]]; then
|
||||
# Uninstall mode: only protect system-critical components
|
||||
# Uninstall mode: first check if it's an uninstallable Apple app
|
||||
for pattern in "${APPLE_UNINSTALLABLE_APPS[@]}"; do
|
||||
if bundle_matches_pattern "$path" "$pattern"; then
|
||||
return 1 # Can be uninstalled
|
||||
fi
|
||||
done
|
||||
# Then check system-critical components
|
||||
for pattern in "${SYSTEM_CRITICAL_BUNDLES[@]}"; do
|
||||
if bundle_matches_pattern "$path" "$pattern"; then
|
||||
return 0
|
||||
|
||||
@@ -160,6 +160,32 @@ EOF
|
||||
[ "$result" = "protected" ]
|
||||
}
|
||||
|
||||
@test "Apple apps from App Store can be uninstalled (Issue #386)" {
|
||||
# Xcode should NOT be protected from uninstall
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; should_protect_from_uninstall 'com.apple.dt.Xcode' && echo 'protected' || echo 'not-protected'")
|
||||
[ "$result" = "not-protected" ]
|
||||
|
||||
# Final Cut Pro should NOT be protected from uninstall
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; should_protect_from_uninstall 'com.apple.FinalCutPro' && echo 'protected' || echo 'not-protected'")
|
||||
[ "$result" = "not-protected" ]
|
||||
|
||||
# GarageBand should NOT be protected from uninstall
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; should_protect_from_uninstall 'com.apple.GarageBand' && echo 'protected' || echo 'not-protected'")
|
||||
[ "$result" = "not-protected" ]
|
||||
|
||||
# iWork apps should NOT be protected from uninstall
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; should_protect_from_uninstall 'com.apple.iWork.Pages' && echo 'protected' || echo 'not-protected'")
|
||||
[ "$result" = "not-protected" ]
|
||||
|
||||
# But Safari (system app) should still be protected
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; should_protect_from_uninstall 'com.apple.Safari' && echo 'protected' || echo 'not-protected'")
|
||||
[ "$result" = "protected" ]
|
||||
|
||||
# And Finder should still be protected
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; should_protect_from_uninstall 'com.apple.finder' && echo 'protected' || echo 'not-protected'")
|
||||
[ "$result" = "protected" ]
|
||||
}
|
||||
|
||||
@test "print_summary_block formats output correctly" {
|
||||
result=$(HOME="$HOME" bash --noprofile --norc -c "source '$PROJECT_ROOT/lib/core/common.sh'; print_summary_block 'success' 'Test Summary' 'Detail 1' 'Detail 2'")
|
||||
[[ "$result" == *"Test Summary"* ]]
|
||||
|
||||
Reference in New Issue
Block a user