Update Fleet-maintained apps - #50112
Conversation
Generated automatically with cmd/maintained-apps.
Script Diff Resultsee/maintained-apps/outputs/1password/darwin.json=== Install Script (no changes) ===
=== Uninstall // c927cf5a -> a642a51c ===
--- /tmp/old.1H4r2r 2026-07-29 02:52:06.984595649 +0000
+++ /tmp/new.UG7F4o 2026-07-29 02:52:06.984595649 +0000
@@ -45,6 +45,76 @@
}
+remove_launchctl_service() {
+ local service="$1"
+ local booleans=("true" "false")
+ local plist_status
+ local paths
+ local should_sudo
+
+ echo "Removing launchctl service ${service}"
+
+ # A wildcard label can't be used with launchctl or as a plist name, so expand
+ # it to the labels of currently loaded services that match the pattern.
+ local services=("$service")
+ if [[ "$service" == *"*"* ]]; then
+ local regex
+ # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so
+ # it matches a full label rather than a substring.
+ regex=$(printf '%s' "$service" | sed -e 's/[][(){}.^$+?|\\]/\\&/g' -e 's/\*/.*/g')
+ regex="^${regex}$"
+ services=()
+ local id
+ # Match every loaded job by label regardless of PID; launchctl list reports
+ # loaded-but-not-running jobs with a "-" in the PID column.
+ while read -r _ _ id; do
+ [[ "$id" =~ $regex ]] && services+=("$id")
+ done < <(launchctl list 2>/dev/null | tail -n +2)
+ if [[ ${#services[@]} -eq 0 ]]; then
+ echo "No loaded launchctl service matches ${service}"
+ return
+ fi
+ fi
+
+ local service_label
+ for service_label in "${services[@]}"; do
+ for should_sudo in "${booleans[@]}"; do
+ plist_status=$(launchctl list "${service_label}" 2>/dev/null)
+
+ if [[ $plist_status == \{* ]]; then
+ if [[ $should_sudo == "true" ]]; then
+ sudo launchctl remove "${service_label}"
+ else
+ launchctl remove "${service_label}"
+ fi
+ sleep 1
+ fi
+
+ paths=(
+ "/Library/LaunchAgents/${service_label}.plist"
+ "/Library/LaunchDaemons/${service_label}.plist"
+ )
+
+ # if not using sudo, prepend the home directory to the paths
+ if [[ $should_sudo == "false" ]]; then
+ for i in "${!paths[@]}"; do
+ paths[i]="${HOME}${paths[i]}"
+ done
+ fi
+
+ for path in "${paths[@]}"; do
+ if [[ -e "$path" ]]; then
+ if [[ $should_sudo == "true" ]]; then
+ sudo rm -f -- "$path"
+ else
+ rm -f -- "$path"
+ fi
+ fi
+ done
+ done
+ done
+}
+
trash() {
local logged_in_user="$1"
local target_file="$2"
@@ -92,6 +162,8 @@
fi
}
+remove_launchctl_service '2BUA8C4S2C.com.1password.browser-helper'
+remove_launchctl_service 'com.1password.1password-launcher'
quit_application 'com.1password.1password'
sudo rm -rf "$APPDIR/1Password.app"
trash $LOGGED_IN_USER '~/Library/Application Scripts/2BUA8C4S2C.com.1password*'ee/maintained-apps/outputs/activedock/darwin.json=== Install Script (no changes) ===
=== Uninstall // 9850444d -> 62b94363 ===
--- /tmp/old.1D3MfY 2026-07-29 02:52:07.018594249 +0000
+++ /tmp/new.vExmKp 2026-07-29 02:52:07.018594249 +0000
@@ -54,6 +54,7 @@
sudo rm -rf "$APPDIR/ActiveDock 2.app"
trash $LOGGED_IN_USER '~/Library/Application Support/ActiveDock 2'
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.sergey-gerasimenko.activedock-2.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/com.sergey-gerasimenko.ActiveDock-2'
trash $LOGGED_IN_USER '~/Library/Caches/com.sergey-gerasimenko.ActiveDock-2'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.sergey-gerasimenko.ActiveDock-2'ee/maintained-apps/outputs/antigravity/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/anyburn/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/anytype/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/appium-inspector/darwin.json=== Install Script (no changes) ===
=== Uninstall // 84d10064 -> 123508e6 ===
--- /tmp/old.wZyO56 2026-07-29 02:52:07.126589803 +0000
+++ /tmp/new.Dznj0p 2026-07-29 02:52:07.126589803 +0000
@@ -54,6 +54,7 @@
sudo rm -rf "$APPDIR/Appium Inspector.app"
trash $LOGGED_IN_USER '~/Library/Application Support/appium-inspector'
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/io.appium.inspector.sfl*'
trash $LOGGED_IN_USER '~/Library/Logs/Appium Inspector'
trash $LOGGED_IN_USER '~/Library/Preferences/io.appium.inspector.plist'
trash $LOGGED_IN_USER '~/Library/Saved Application State/io.appium.inspector.savedState'ee/maintained-apps/outputs/aptakube/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/aws-cli/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/aws-vpn-client/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/azul-zulu-25-jre/windows.json=== Install Script (no changes) ===
=== Uninstall // ef6bb3e7 -> 6129996f ===
--- /tmp/old.lR6nm2 2026-07-29 02:52:07.463575931 +0000
+++ /tmp/new.9U4mov 2026-07-29 02:52:07.463575931 +0000
@@ -1,4 +1,4 @@
-$product_code = '{28ED6065-4CBD-47B6-9010-582DD8465EFC}'
+$product_code = '{9BA5257B-93C3-4E9B-A90D-39DFA157A7AA}'
$timeoutSeconds = 300 # 5 minute timeout
# Fleet uninstalls app using product code that's extracted on uploadee/maintained-apps/outputs/bartender/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/chatbox/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/chatgpt-atlas/darwin.json=== Install Script (no changes) ===
=== Uninstall // e792c12a -> 179b26c0 ===
--- /tmp/old.pkfhTb 2026-07-29 02:52:07.562571855 +0000
+++ /tmp/new.FrUhYw 2026-07-29 02:52:07.562571855 +0000
@@ -171,6 +171,7 @@
trash $LOGGED_IN_USER '~/Library/Caches/com.openai.atlas'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.openai.atlas'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.openai.atlas.binarycookies'
+trash $LOGGED_IN_USER '~/Library/LaunchAgents/com.openai.atlas.update-helper.plist'
trash $LOGGED_IN_USER '~/Library/Logs/DiagnosticReports/ChatGPT Atlas (Service)*.ips'
trash $LOGGED_IN_USER '~/Library/Preferences/com.openai.atlas.plist'
trash $LOGGED_IN_USER '~/Library/Preferences/com.openai.atlas.web.plist'ee/maintained-apps/outputs/cmake-app/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/crashplan/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/cursor/darwin.json=== Install Script (no changes) ===
=== Uninstall // 9d80ae1c -> 03b9aece ===
--- /tmp/old.YrFF0N 2026-07-29 02:52:07.665567615 +0000
+++ /tmp/new.8HOQdr 2026-07-29 02:52:07.665567615 +0000
@@ -57,6 +57,7 @@
trash $LOGGED_IN_USER '~/.cursor'
trash $LOGGED_IN_USER '~/.cursor-tutor'
trash $LOGGED_IN_USER '~/Library/Application Support/Caches/cursor-updater'
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.todesktop.230313mzl4w4u92.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/Cursor'
trash $LOGGED_IN_USER '~/Library/Caches/com.todesktop.*'
trash $LOGGED_IN_USER '~/Library/Caches/com.todesktop.*.ShipIt'ee/maintained-apps/outputs/cycling74-max/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/dataflare/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/dataflare/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/delinea-connection-manager/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/discord/darwin.json=== Install Script (no changes) ===
=== Uninstall // 46a242eb -> 450a6520 ===
--- /tmp/old.yLzHoC 2026-07-29 02:52:07.821561194 +0000
+++ /tmp/new.SDFtq4 2026-07-29 02:52:07.821561194 +0000
@@ -45,6 +45,76 @@
}
+remove_launchctl_service() {
+ local service="$1"
+ local booleans=("true" "false")
+ local plist_status
+ local paths
+ local should_sudo
+
+ echo "Removing launchctl service ${service}"
+
+ # A wildcard label can't be used with launchctl or as a plist name, so expand
+ # it to the labels of currently loaded services that match the pattern.
+ local services=("$service")
+ if [[ "$service" == *"*"* ]]; then
+ local regex
+ # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so
+ # it matches a full label rather than a substring.
+ regex=$(printf '%s' "$service" | sed -e 's/[][(){}.^$+?|\\]/\\&/g' -e 's/\*/.*/g')
+ regex="^${regex}$"
+ services=()
+ local id
+ # Match every loaded job by label regardless of PID; launchctl list reports
+ # loaded-but-not-running jobs with a "-" in the PID column.
+ while read -r _ _ id; do
+ [[ "$id" =~ $regex ]] && services+=("$id")
+ done < <(launchctl list 2>/dev/null | tail -n +2)
+ if [[ ${#services[@]} -eq 0 ]]; then
+ echo "No loaded launchctl service matches ${service}"
+ return
+ fi
+ fi
+
+ local service_label
+ for service_label in "${services[@]}"; do
+ for should_sudo in "${booleans[@]}"; do
+ plist_status=$(launchctl list "${service_label}" 2>/dev/null)
+
+ if [[ $plist_status == \{* ]]; then
+ if [[ $should_sudo == "true" ]]; then
+ sudo launchctl remove "${service_label}"
+ else
+ launchctl remove "${service_label}"
+ fi
+ sleep 1
+ fi
+
+ paths=(
+ "/Library/LaunchAgents/${service_label}.plist"
+ "/Library/LaunchDaemons/${service_label}.plist"
+ )
+
+ # if not using sudo, prepend the home directory to the paths
+ if [[ $should_sudo == "false" ]]; then
+ for i in "${!paths[@]}"; do
+ paths[i]="${HOME}${paths[i]}"
+ done
+ fi
+
+ for path in "${paths[@]}"; do
+ if [[ -e "$path" ]]; then
+ if [[ $should_sudo == "true" ]]; then
+ sudo rm -f -- "$path"
+ else
+ rm -f -- "$path"
+ fi
+ fi
+ done
+ done
+ done
+}
+
trash() {
local logged_in_user="$1"
local target_file="$2"
@@ -92,6 +162,7 @@
fi
}
+remove_launchctl_service 'com.discord.discord.ShipIt'
quit_application 'com.hnc.Discord'
quit_application 'com.hnc.Discord.helper.Plugin'
quit_application 'com.hnc.Discord.helper.Renderer'
@@ -104,6 +175,7 @@
trash $LOGGED_IN_USER '~/Library/Cookies/com.hnc.Discord.binarycookies'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.hnc.Discord'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.hnc.Discord.binarycookies'
+trash $LOGGED_IN_USER '~/Library/Preferences/ByHost/com.discord.discord.ShipIt.*.plist'
trash $LOGGED_IN_USER '~/Library/Preferences/com.hnc.Discord.helper.plist'
trash $LOGGED_IN_USER '~/Library/Preferences/com.hnc.Discord.plist'
trash $LOGGED_IN_USER '~/Library/Saved Application State/com.hnc.Discord.savedState'ee/maintained-apps/outputs/docker/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/drawio/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/elgato-stream-deck/darwin.json=== Install // 214a13cd -> 81223e72 ===
--- /tmp/old.s84V70 2026-07-29 02:52:07.915557324 +0000
+++ /tmp/new.CqLSdZ 2026-07-29 02:52:07.916557283 +0000
@@ -96,5 +96,5 @@
# install pkg files
quit_and_track_application 'com.elgato.StreamDeck'
-sudo installer -pkg "$TMPDIR/Stream_Deck_7.5.0.22885.pkg" -target /
+sudo installer -pkg "$TMPDIR/Stream_Deck_7.5.1.22901.pkg" -target /
relaunch_application 'com.elgato.StreamDeck'
=== Uninstall // b842b140 -> aff3ed62 ===
--- /tmp/old.UfAhlm 2026-07-29 02:52:07.928556789 +0000
+++ /tmp/new.0Bl0BO 2026-07-29 02:52:07.928556789 +0000
@@ -229,6 +229,7 @@
}
remove_launchctl_service 'com.elgato.StreamDeck*'
+remove_launchctl_service 'com.elgato.StreamDeck.trampoline'
quit_application 'com.elgato.StreamDeck'
remove_pkg_files 'com.elgato.StreamDeck'
forget_pkg 'com.elgato.StreamDeck'ee/maintained-apps/outputs/elgato-stream-deck/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/etrecheckpro/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/extradock/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/figma/darwin.json=== Install Script (no changes) ===
=== Uninstall // 5fe54a7b -> ffdf9bc3 ===
--- /tmp/old.oFD6bY 2026-07-29 02:52:08.052551685 +0000
+++ /tmp/new.wg77tQ 2026-07-29 02:52:08.052551685 +0000
@@ -94,9 +94,11 @@
quit_application 'com.figma.agent'
sudo rm -rf "$APPDIR/Figma.app"
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.figma.desktop.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/Figma'
trash $LOGGED_IN_USER '~/Library/Application Support/figma-desktop'
trash $LOGGED_IN_USER '~/Library/Caches/com.figma.agent'
trash $LOGGED_IN_USER '~/Library/Caches/com.figma.Desktop'
+trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.figma.agent'
trash $LOGGED_IN_USER '~/Library/Preferences/com.figma.Desktop.plist'
trash $LOGGED_IN_USER '~/Library/Saved Application State/com.figma.Desktop.savedState'ee/maintained-apps/outputs/figma/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/firefox/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/firefox/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/firefox@developer-edition/darwin.json=== Install Script (no changes) ===
=== Uninstall // b108b0ff -> 292c5733 ===
--- /tmp/old.gyzOaQ 2026-07-29 02:52:08.158547321 +0000
+++ /tmp/new.VjNBms 2026-07-29 02:52:08.158547321 +0000
@@ -65,5 +65,6 @@
trash $LOGGED_IN_USER '~/Library/Caches/Mozilla/updates/Applications/Firefox'
trash $LOGGED_IN_USER '~/Library/Caches/org.mozilla.firefox'
trash $LOGGED_IN_USER '~/Library/Preferences/org.mozilla.firefox.plist'
+trash $LOGGED_IN_USER '~/Library/Preferences/org.mozilla.firefoxdeveloperedition.plist'
trash $LOGGED_IN_USER '~/Library/Saved Application State/org.mozilla.firefox.savedState'
trash $LOGGED_IN_USER '~/Library/WebKit/org.mozilla.firefox'ee/maintained-apps/outputs/firefox@nightly/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/firefox@nightly/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/forklift/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/framer/darwin.json=== Install Script (no changes) ===
=== Uninstall // 4775195c -> 12495d2a ===
--- /tmp/old.AkpH21 2026-07-29 02:52:08.283542175 +0000
+++ /tmp/new.2Twj6p 2026-07-29 02:52:08.283542175 +0000
@@ -53,6 +53,7 @@
}
sudo rm -rf "$APPDIR/Framer.app"
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.framer.electron.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/Framer'
trash $LOGGED_IN_USER '~/Library/Caches/com.framer.electron'
trash $LOGGED_IN_USER '~/Library/Caches/com.framer.electron.ShipIt'ee/maintained-apps/outputs/gdevelop/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/gdevelop/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/gitify/darwin.json=== Install Script (no changes) ===
=== Uninstall // 65bf9482 -> 33618979 ===
--- /tmp/old.mLFuob 2026-07-29 02:52:08.373538471 +0000
+++ /tmp/new.F8Y68v 2026-07-29 02:52:08.373538471 +0000
@@ -100,5 +100,6 @@
trash $LOGGED_IN_USER '~/Library/Caches/com.electron.gitify*'
trash $LOGGED_IN_USER '~/Library/Caches/gitify-updater'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.electron.gitify'
+trash $LOGGED_IN_USER '~/Library/Logs/gitify'
trash $LOGGED_IN_USER '~/Library/Preferences/com.electron.gitify*.plist'
trash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.gitify.savedState'ee/maintained-apps/outputs/grammarly-desktop/darwin.json=== Install Script (no changes) ===
=== Uninstall // 8ac93526 -> 7dff0961 ===
--- /tmp/old.Sex9VQ 2026-07-29 02:52:08.408537030 +0000
+++ /tmp/new.ZcK2IW 2026-07-29 02:52:08.409536989 +0000
@@ -126,12 +126,14 @@
remove_launchctl_service 'com.grammarly.ProjectLlama.Shepherd'
remove_launchctl_service 'com.grammarly.ProjectLlama.Uninstaller'
sudo rm -rf "$APPDIR/Grammarly Desktop.app"
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.grammarly.projectllama.loginhelper.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/com.grammarly.ProjectLlama'
trash $LOGGED_IN_USER '~/Library/Caches/com.grammarly.ProjectLlama'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.grammarly.GRLlamaOnboarding.binarycookies'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.grammarly.ProjectLlama'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.grammarly.ProjectLlama.binarycookies'
trash $LOGGED_IN_USER '~/Library/LaunchAgents/com.grammarly.ProjectLlama.Shepherd.plist'
+trash $LOGGED_IN_USER '~/Library/LaunchAgents/com.grammarly.ProjectLlama.Uninstaller.plist'
trash $LOGGED_IN_USER '~/Library/Preferences/com.grammarly.ProjectLlama.plist'
trash $LOGGED_IN_USER '~/Library/WebKit/com.grammarly.GRLlamaOnboarding'
trash $LOGGED_IN_USER '~/Library/WebKit/com.grammarly.ProjectLlama'ee/maintained-apps/outputs/granola/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/granola/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/hive-app/darwin.json=== Install Script (no changes) ===
=== Uninstall // 78bb4e43 -> 951b5587 ===
--- /tmp/old.ry8CQp 2026-07-29 02:52:08.487533778 +0000
+++ /tmp/new.X8lUlI 2026-07-29 02:52:08.487533778 +0000
@@ -54,6 +54,7 @@
sudo rm -rf "$APPDIR/Hive.app"
trash $LOGGED_IN_USER '~/.hive'
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.hive.app.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/hive'
trash $LOGGED_IN_USER '~/Library/Logs/hive'
trash $LOGGED_IN_USER '~/Library/Preferences/com.hive.app.plist'ee/maintained-apps/outputs/jamovi/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/kaleidoscope/darwin.json=== Install Script (no changes) ===
=== Uninstall // c6bb8769 -> 1e1dcbc9 ===
--- /tmp/old.LkfFAI 2026-07-29 02:52:08.567530485 +0000
+++ /tmp/new.odhxRF 2026-07-29 02:52:08.567530485 +0000
@@ -159,7 +159,7 @@
fi
}
-quit_application 'app.kaleidoscope.v6'
+quit_application 'app.kaleidoscope.v7'
remove_pkg_files 'app.kaleidoscope.uninstall_ksdiff'
forget_pkg 'app.kaleidoscope.uninstall_ksdiff'
sudo rm -rf "$APPDIR/Kaleidoscope.app"ee/maintained-apps/outputs/kiro-cli/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/kiro/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/kiro/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/loom/darwin.json=== Install Script (no changes) ===
=== Uninstall // f408ec47 -> 1a901a1f ===
--- /tmp/old.Fg0WVY 2026-07-29 02:52:08.668526327 +0000
+++ /tmp/new.jq4VyM 2026-07-29 02:52:08.668526327 +0000
@@ -53,6 +53,7 @@
}
sudo rm -rf "$APPDIR/Loom.app"
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.loom.desktop.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/Loom'
trash $LOGGED_IN_USER '~/Library/Logs/Loom'
trash $LOGGED_IN_USER '~/Library/Preferences/com.loom.desktop.plist'ee/maintained-apps/outputs/lulu/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/maccy/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/malwarebytes/darwin.json=== Install // eb844ac0 -> d6b1d4ec ===
--- /tmp/old.nUHAbI 2026-07-29 02:52:08.782521634 +0000
+++ /tmp/new.yjQqv2 2026-07-29 02:52:08.782521634 +0000
@@ -96,5 +96,5 @@
# install pkg files
quit_and_track_application 'com.malwarebytes.mbam.frontend.application'
-sudo installer -pkg "$TMPDIR/Malwarebytes-Mac-5.24.0.4031.pkg" -target /
+sudo installer -pkg "$TMPDIR/Malwarebytes-Mac-5.25.2.4106.pkg" -target /
relaunch_application 'com.malwarebytes.mbam.frontend.application'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/microsoft-auto-update/darwin.json=== Install // 64b51d51 -> 758dae4d ===
--- /tmp/old.A6O04j 2026-07-29 02:52:08.829519699 +0000
+++ /tmp/new.ZRWUzm 2026-07-29 02:52:08.829519699 +0000
@@ -96,5 +96,5 @@
# install pkg files
quit_and_track_application 'com.microsoft.autoupdate2'
-sudo installer -pkg "$TMPDIR/Microsoft_AutoUpdate_4.83.26040910_Updater.pkg" -target /
+sudo installer -pkg "$TMPDIR/Microsoft_AutoUpdate_4.84.26071119_Updater.pkg" -target /
relaunch_application 'com.microsoft.autoupdate2'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/microsoft-excel/darwin.json=== Install // a058ee4b -> 98c4e79f ===
--- /tmp/old.5pYPY2 2026-07-29 02:52:08.868518094 +0000
+++ /tmp/new.baL78R 2026-07-29 02:52:08.868518094 +0000
@@ -117,6 +117,6 @@
EOF
-sudo installer -pkg "$TMPDIR"/Microsoft_Excel_16.111.26071913_Installer.pkg -target / -applyChoiceChangesXML "$CHOICE_XML"
+sudo installer -pkg "$TMPDIR"/Microsoft_Excel_16.111.26072617_Installer.pkg -target / -applyChoiceChangesXML "$CHOICE_XML"
relaunch_application 'com.microsoft.Excel'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/microsoft-onenote/darwin.json=== Install // fe16d50a -> 0ac5b395 ===
--- /tmp/old.aiPRvj 2026-07-29 02:52:08.906516530 +0000
+++ /tmp/new.dTbpKc 2026-07-29 02:52:08.906516530 +0000
@@ -96,5 +96,5 @@
# install pkg files
quit_and_track_application 'com.microsoft.onenote.mac'
-sudo installer -pkg "$TMPDIR/Microsoft_OneNote_16.111.26071913_Updater.pkg" -target /
+sudo installer -pkg "$TMPDIR/Microsoft_OneNote_16.111.26072617_Updater.pkg" -target /
relaunch_application 'com.microsoft.onenote.mac'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/microsoft-powerpoint/darwin.json=== Install // daf855a0 -> 36641a79 ===
--- /tmp/old.Ae4kHy 2026-07-29 02:52:08.944514965 +0000
+++ /tmp/new.y2Yqi4 2026-07-29 02:52:08.944514965 +0000
@@ -117,6 +117,6 @@
EOF
-sudo installer -pkg "$TMPDIR"/Microsoft_PowerPoint_16.111.26071913_Installer.pkg -target / -applyChoiceChangesXML "$CHOICE_XML"
+sudo installer -pkg "$TMPDIR"/Microsoft_PowerPoint_16.111.26072617_Installer.pkg -target / -applyChoiceChangesXML "$CHOICE_XML"
relaunch_application 'com.microsoft.Powerpoint'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/microsoft-word/darwin.json=== Install // e06030dd -> b470c108 ===
--- /tmp/old.Wl4S3h 2026-07-29 02:52:08.983513360 +0000
+++ /tmp/new.zZ4uMG 2026-07-29 02:52:08.983513360 +0000
@@ -117,6 +117,6 @@
EOF
-sudo installer -pkg "$TMPDIR"/Microsoft_Word_16.111.26071913_Installer.pkg -target / -applyChoiceChangesXML "$CHOICE_XML"
+sudo installer -pkg "$TMPDIR"/Microsoft_Word_16.111.26072617_Installer.pkg -target / -applyChoiceChangesXML "$CHOICE_XML"
relaunch_application 'com.microsoft.Word'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/milanote/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/nextcloud/darwin.json=== Install // c18d4d3b -> d9838806 ===
--- /tmp/old.IbqZtg 2026-07-29 02:52:09.055510396 +0000
+++ /tmp/new.W7KNPP 2026-07-29 02:52:09.055510396 +0000
@@ -96,5 +96,5 @@
# install pkg files
quit_and_track_application 'com.nextcloud.desktopclient'
-sudo installer -pkg "$TMPDIR/Nextcloud-33.0.7.pkg" -target /
+sudo installer -pkg "$TMPDIR/Nextcloud-34.0.0.pkg" -target /
relaunch_application 'com.nextcloud.desktopclient'
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/nextcloud/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/nordlayer/darwin.json=== Install Script (no changes) ===
=== Uninstall // 97f61740 -> 4ab665bb ===
--- /tmp/old.gkAMwD 2026-07-29 02:52:09.127507432 +0000
+++ /tmp/new.qERsye 2026-07-29 02:52:09.127507432 +0000
@@ -235,9 +235,11 @@
remove_pkg_files 'com.nordvpn.macos.teams'
forget_pkg 'com.nordvpn.macos.teams'
trash $LOGGED_IN_USER '~/Library/Application Scripts/com.nordvpn.macos.teams'
+trash $LOGGED_IN_USER '~/Library/Application Scripts/group.com.nordlayer.macos'
trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.nordvpn.macos.teams.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/com.nordvpn.macos.teams'
trash $LOGGED_IN_USER '~/Library/Caches/com.nordvpn.macos.teams'
trash $LOGGED_IN_USER '~/Library/Containers/com.nordvpn.macos.teams'
+trash $LOGGED_IN_USER '~/Library/Group Containers/group.com.nordlayer.macos'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.nordvpn.macos.teams'
trash $LOGGED_IN_USER '~/Library/Preferences/com.nordvpn.macos.teams.plist'ee/maintained-apps/outputs/notion/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/omnioutliner/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/onionshare/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/opencode-desktop/darwin.json=== Install Script (no changes) ===
=== Uninstall // ad62b190 -> 99fcb3f1 ===
--- /tmp/old.kCKFbU 2026-07-29 02:52:09.274501381 +0000
+++ /tmp/new.QRDivB 2026-07-29 02:52:09.274501381 +0000
@@ -54,6 +54,7 @@
sudo rm -rf "$APPDIR/OpenCode.app"
trash $LOGGED_IN_USER '~/Library/Application Support/ai.opencode.desktop'
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/ai.opencode.desktop.sfl*'
trash $LOGGED_IN_USER '~/Library/Caches/ai.opencode.desktop'
trash $LOGGED_IN_USER '~/Library/HTTPStorages/ai.opencode.desktop'
trash $LOGGED_IN_USER '~/Library/Logs/ai.opencode.desktop'ee/maintained-apps/outputs/postman/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/raindropio/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/remote-desktop-manager/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/rightfont/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/roboform/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/spokenly/darwin.json=== Install Script (no changes) ===
=== Uninstall // a5d6883d -> 99a71452 ===
--- /tmp/old.WAaNdG 2026-07-29 02:52:09.486492654 +0000
+++ /tmp/new.D6m9CE 2026-07-29 02:52:09.486492654 +0000
@@ -53,6 +53,8 @@
}
sudo rm -rf "$APPDIR/Spokenly.app"
+trash $LOGGED_IN_USER '~/Library/Application Support/app.spokenly.revenuecat'
trash $LOGGED_IN_USER '~/Library/Application Support/Spokenly'
trash $LOGGED_IN_USER '~/Library/Caches/app.spokenly'
+trash $LOGGED_IN_USER '~/Library/HTTPStorages/app.spokenly'
trash $LOGGED_IN_USER '~/Library/Preferences/app.spokenly.plist'ee/maintained-apps/outputs/spyder/windows.json=== Install Script (no changes) ===
=== Uninstall // 6335aa0a -> 1fb72c38 ===
--- /tmp/old.Mt8iFk 2026-07-29 02:52:09.519491296 +0000
+++ /tmp/new.96MwA6 2026-07-29 02:52:09.520491254 +0000
@@ -30,7 +30,7 @@
$exitCode = $process.ExitCode; Write-Host "Uninstall exit code: $exitCode"; break
}
}
- if (-not $foundUninstaller) { Write-Host "Uninstaller for '$softwareName' not found."; Exit 1 }
+ if (-not $foundUninstaller) { Write-Host "Uninstaller for '$softwareName' not found."; Exit 0 }
} catch { Write-Host "Error: $_"; Exit 1 }
Exit $exitCodeee/maintained-apps/outputs/sql-server-management-studio/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/tableplus/darwin.json=== Install Script (no changes) ===
=== Uninstall // 20e49d94 -> 19abdcd7 ===
--- /tmp/old.BZ7pMJ 2026-07-29 02:52:09.583488661 +0000
+++ /tmp/new.9b1MvI 2026-07-29 02:52:09.583488661 +0000
@@ -53,8 +53,10 @@
}
sudo rm -rf "$APPDIR/TablePlus.app"
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.tinyapp.tableplus.sfl*'
trash $LOGGED_IN_USER '~/Library/Application Support/com.tinyapp.TablePlus'
trash $LOGGED_IN_USER '~/Library/Caches/com.tinyapp.TablePlus'
trash $LOGGED_IN_USER '~/Library/Cookies/com.tinyapp.TablePlus.binarycookies'
+trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.tinyapp.TablePlus'
trash $LOGGED_IN_USER '~/Library/Preferences/com.tinyapp.TablePlus.plist'
trash $LOGGED_IN_USER '~/Library/Saved Application State/com.tinyapp.TablePlus.savedState'ee/maintained-apps/outputs/tabtab/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/tailscale/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/teamviewer/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/thaw/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/thunderbird/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/thunderbird/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/webcatalog/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/wechat/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/whatsapp/darwin.json=== Install Script (no changes) ===
=== Uninstall // 0b25ddc3 -> cd8944ef ===
--- /tmp/old.gesYbK 2026-07-29 02:52:09.881476394 +0000
+++ /tmp/new.6VUxin 2026-07-29 02:52:09.881476394 +0000
@@ -94,6 +94,10 @@
quit_application 'net.whatsapp.WhatsApp'
sudo rm -rf "$APPDIR/WhatsApp.app"
+trash $LOGGED_IN_USER '~/Library/Application Scripts/group.net.whatsapp.family'
+trash $LOGGED_IN_USER '~/Library/Application Scripts/group.net.whatsapp.WhatsApp.private'
+trash $LOGGED_IN_USER '~/Library/Application Scripts/group.net.whatsapp.WhatsApp.shared'
+trash $LOGGED_IN_USER '~/Library/Application Scripts/group.net.whatsapp.WhatsAppSMB.shared'
trash $LOGGED_IN_USER '~/Library/Application Scripts/net.whatsapp.WhatsApp*'
trash $LOGGED_IN_USER '~/Library/Caches/net.whatsapp.WhatsApp'
trash $LOGGED_IN_USER '~/Library/Containers/net.whatsapp.WhatsApp*'ee/maintained-apps/outputs/workflowy/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) === |
|
Closing in favor of #50113. |
WalkthroughUpdated numerous Fleet-maintained app manifests with newer versions, patch-detection thresholds, installer URLs, and SHA-256 checksums across macOS and Windows outputs. Several entries now reference revised uninstall scripts with expanded launchctl, plist, shared-file-list, Library, and application-data cleanup. Installer scripts for selected Microsoft, Malwarebytes, Nextcloud, and Elgato packages now reference updated package artifacts. One Thaw installer URL changed repository ownership, and Spyder’s no-uninstaller result is now successful. Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ee/maintained-apps/outputs/1password/darwin.json`:
- Line 20: Update remove_launchctl_service to check and remove services through
explicit system and logged-in-user GUI launchd domains rather than relying on
the caller’s default domain. Derive the user domain from LOGGED_IN_USER and its
UID, and construct user LaunchAgent paths from /Users/$LOGGED_IN_USER instead of
$HOME, while preserving the existing sudo handling for system operations.
In `@ee/maintained-apps/outputs/cursor/darwin.json`:
- Around line 19-20: Update the uninstall script’s `sudo rm -rf 'cursor'`
command to target the same absolute CLI-link path created by the installer’s
`/bin/ln` command, and remove it with `rm --` rather than recursive deletion.
Ensure the installer and uninstaller consistently reference that absolute
expected symlink path.
In `@ee/maintained-apps/outputs/discord/darwin.json`:
- Line 19: The launchAgent cleanup in remove_launchctl_service currently uses
the root launchd domain and /root when run as root. In
ee/maintained-apps/outputs/discord/darwin.json:19-19, update cleanup for
com.discord.discord.ShipIt to resolve the console user’s UID and home directory,
run launchctl list/remove against gui/<uid>, and remove the plist from that
user’s home LaunchAgents directory; apply the same change to
com.openai.atlas.update-helper in
ee/maintained-apps/outputs/chatgpt-atlas/darwin.json:19-19.
In `@ee/maintained-apps/outputs/elgato-stream-deck/darwin.json`:
- Line 20: Update remove_launchctl_service so wildcard patterns still remove
matching plist files when no matching launchctl service is loaded; do not return
before the path-cleanup loops. Preserve the explicit service handling and ensure
the stale com.elgato.StreamDeck.trampoline plist is cleaned up, since the quoted
~/Library fallback is ineffective.
In `@ee/maintained-apps/outputs/figma/darwin.json`:
- Line 20: Update the uninstall sequence around quit_application to also quit
the managed Figma desktop bundle ID, com.figma.Desktop, before removing
Figma.app; retain the existing com.figma.agent shutdown and cleanup behavior.
In `@ee/maintained-apps/outputs/firefox`@developer-edition/darwin.json:
- Around line 11-19: Update uninstall script ref 292c5733 to remove only Firefox
Developer Edition data, replacing regular Firefox paths and identifiers such as
~/Library/Application Support/Firefox, org.mozilla.firefox, and firefox_* with
their Developer Edition-specific equivalents matching
org.mozilla.firefoxdeveloperedition. Preserve cleanup of shared Mozilla
directories only where it cannot affect regular Firefox data.
In `@ee/maintained-apps/outputs/kaleidoscope/darwin.json`:
- Around line 4-7: Update the Kaleidoscope package’s detection queries and all
related installer, quit, relaunch, and uninstallant references from
app.kaleidoscope.v6 to app.kaleidoscope.v7, while preserving the existing
version checks and operation flow.
In `@ee/maintained-apps/outputs/nordlayer/darwin.json`:
- Line 20: Validate LOGGED_IN_USER after it is populated, and only execute the
subsequent user-specific trash calls when it is non-empty and not root or
loginwindow. Quote the LOGGED_IN_USER argument at each trash invocation,
preserving the existing cleanup behavior for valid console users.
In `@ee/maintained-apps/outputs/tableplus/darwin.json`:
- Line 19: Update the shared-file-list cleanup argument in the script to use the
exact case-sensitive filename prefix com.tinyapp.TablePlus.sfl*. Leave the trash
function and other cleanup paths unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3240b6e1-0dff-4800-9e52-360551c3093c
📒 Files selected for processing (84)
ee/maintained-apps/outputs/1password/darwin.jsonee/maintained-apps/outputs/activedock/darwin.jsonee/maintained-apps/outputs/antigravity/darwin.jsonee/maintained-apps/outputs/anyburn/windows.jsonee/maintained-apps/outputs/anytype/darwin.jsonee/maintained-apps/outputs/appium-inspector/darwin.jsonee/maintained-apps/outputs/aptakube/windows.jsonee/maintained-apps/outputs/aws-cli/windows.jsonee/maintained-apps/outputs/aws-vpn-client/darwin.jsonee/maintained-apps/outputs/azul-zulu-25-jre/windows.jsonee/maintained-apps/outputs/bartender/darwin.jsonee/maintained-apps/outputs/chatbox/windows.jsonee/maintained-apps/outputs/chatgpt-atlas/darwin.jsonee/maintained-apps/outputs/cmake-app/darwin.jsonee/maintained-apps/outputs/crashplan/windows.jsonee/maintained-apps/outputs/cursor/darwin.jsonee/maintained-apps/outputs/cycling74-max/darwin.jsonee/maintained-apps/outputs/dataflare/darwin.jsonee/maintained-apps/outputs/dataflare/windows.jsonee/maintained-apps/outputs/delinea-connection-manager/windows.jsonee/maintained-apps/outputs/discord/darwin.jsonee/maintained-apps/outputs/docker/windows.jsonee/maintained-apps/outputs/drawio/windows.jsonee/maintained-apps/outputs/elgato-stream-deck/darwin.jsonee/maintained-apps/outputs/elgato-stream-deck/windows.jsonee/maintained-apps/outputs/etrecheckpro/darwin.jsonee/maintained-apps/outputs/extradock/darwin.jsonee/maintained-apps/outputs/figma/darwin.jsonee/maintained-apps/outputs/figma/windows.jsonee/maintained-apps/outputs/firefox/darwin.jsonee/maintained-apps/outputs/firefox/windows.jsonee/maintained-apps/outputs/firefox@developer-edition/darwin.jsonee/maintained-apps/outputs/firefox@nightly/darwin.jsonee/maintained-apps/outputs/firefox@nightly/windows.jsonee/maintained-apps/outputs/forklift/darwin.jsonee/maintained-apps/outputs/framer/darwin.jsonee/maintained-apps/outputs/gdevelop/darwin.jsonee/maintained-apps/outputs/gdevelop/windows.jsonee/maintained-apps/outputs/gitify/darwin.jsonee/maintained-apps/outputs/grammarly-desktop/darwin.jsonee/maintained-apps/outputs/granola/darwin.jsonee/maintained-apps/outputs/granola/windows.jsonee/maintained-apps/outputs/hive-app/darwin.jsonee/maintained-apps/outputs/jamovi/darwin.jsonee/maintained-apps/outputs/kaleidoscope/darwin.jsonee/maintained-apps/outputs/kiro-cli/darwin.jsonee/maintained-apps/outputs/kiro/darwin.jsonee/maintained-apps/outputs/kiro/windows.jsonee/maintained-apps/outputs/loom/darwin.jsonee/maintained-apps/outputs/lulu/darwin.jsonee/maintained-apps/outputs/maccy/darwin.jsonee/maintained-apps/outputs/malwarebytes/darwin.jsonee/maintained-apps/outputs/microsoft-auto-update/darwin.jsonee/maintained-apps/outputs/microsoft-excel/darwin.jsonee/maintained-apps/outputs/microsoft-onenote/darwin.jsonee/maintained-apps/outputs/microsoft-powerpoint/darwin.jsonee/maintained-apps/outputs/microsoft-word/darwin.jsonee/maintained-apps/outputs/milanote/darwin.jsonee/maintained-apps/outputs/nextcloud/darwin.jsonee/maintained-apps/outputs/nextcloud/windows.jsonee/maintained-apps/outputs/nordlayer/darwin.jsonee/maintained-apps/outputs/notion/darwin.jsonee/maintained-apps/outputs/omnioutliner/darwin.jsonee/maintained-apps/outputs/onionshare/darwin.jsonee/maintained-apps/outputs/opencode-desktop/darwin.jsonee/maintained-apps/outputs/postman/darwin.jsonee/maintained-apps/outputs/raindropio/darwin.jsonee/maintained-apps/outputs/remote-desktop-manager/darwin.jsonee/maintained-apps/outputs/rightfont/darwin.jsonee/maintained-apps/outputs/roboform/darwin.jsonee/maintained-apps/outputs/spokenly/darwin.jsonee/maintained-apps/outputs/spyder/windows.jsonee/maintained-apps/outputs/sql-server-management-studio/windows.jsonee/maintained-apps/outputs/tableplus/darwin.jsonee/maintained-apps/outputs/tabtab/darwin.jsonee/maintained-apps/outputs/tailscale/windows.jsonee/maintained-apps/outputs/teamviewer/darwin.jsonee/maintained-apps/outputs/thaw/darwin.jsonee/maintained-apps/outputs/thunderbird/darwin.jsonee/maintained-apps/outputs/thunderbird/windows.jsonee/maintained-apps/outputs/webcatalog/darwin.jsonee/maintained-apps/outputs/wechat/darwin.jsonee/maintained-apps/outputs/whatsapp/darwin.jsonee/maintained-apps/outputs/workflowy/darwin.json
| "refs": { | ||
| "1d854c01": "#!/bin/bash\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\nquit_application 'com.1password.1password'\ninstaller -pkg \"$INSTALLER_PATH\" -target /\n\n", | ||
| "c927cf5a": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nquit_application 'com.1password.1password'\nsudo rm -rf \"$APPDIR/1Password.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/2BUA8C4S2C.com.1password*'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/2BUA8C4S2C.com.agilebits'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.1password.1password-launcher'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.1password.browser-support'\ntrash $LOGGED_IN_USER '~/Library/Application Support/1Password'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Arc/User Data/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.1password.1password.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/CrashReporter/1Password*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome Beta/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome Canary/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome Dev/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge Beta/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge Canary/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge Dev/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Mozilla/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Vivaldi/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Containers/2BUA8C4S2C.com.1password.browser-helper'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.1password.1password*'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.1password.browser-support'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/2BUA8C4S2C.com.1password'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/2BUA8C4S2C.com.agilebits'\ntrash $LOGGED_IN_USER '~/Library/Logs/1Password'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.1password.1password.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/group.com.1password.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.1password.1password.savedState'\n" | ||
| "a642a51c": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service '2BUA8C4S2C.com.1password.browser-helper'\nremove_launchctl_service 'com.1password.1password-launcher'\nquit_application 'com.1password.1password'\nsudo rm -rf \"$APPDIR/1Password.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/2BUA8C4S2C.com.1password*'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/2BUA8C4S2C.com.agilebits'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.1password.1password-launcher'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.1password.browser-support'\ntrash $LOGGED_IN_USER '~/Library/Application Support/1Password'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Arc/User Data/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.1password.1password.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/CrashReporter/1Password*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome Beta/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome Canary/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome Dev/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge Beta/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge Canary/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge Dev/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Microsoft Edge/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Mozilla/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Vivaldi/NativeMessagingHosts/com.1password.1password.json'\ntrash $LOGGED_IN_USER '~/Library/Containers/2BUA8C4S2C.com.1password.browser-helper'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.1password.1password*'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.1password.browser-support'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/2BUA8C4S2C.com.1password'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/2BUA8C4S2C.com.agilebits'\ntrash $LOGGED_IN_USER '~/Library/Logs/1Password'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.1password.1password.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/group.com.1password.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.1password.1password.savedState'\n" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use the correct launchd domain for status checks and user paths.
should_sudo only changes the removal command; plist_status=$(launchctl list ...) always checks the caller’s domain. Consequently, system services may never be detected, while user services can be checked in one domain and removed in another. Also, $HOME resolves to /var/root when the uninstall runs as root, so user LaunchAgent plists are not removed from the logged-in user’s home.
Use explicit system/GUI domains and build user paths from LOGGED_IN_USER.
Proposed correction
- plist_status=$(launchctl list "${service_label}" 2>/dev/null)
+ if [[ "$should_sudo" == "true" ]]; then
+ plist_status=$(sudo launchctl list "${service_label}" 2>/dev/null)
+ else
+ plist_status=$(launchctl list "${service_label}" 2>/dev/null)
+ fi
...
- paths[i]="${HOME}${paths[i]}"
+ paths[i]="/Users/${LOGGED_IN_USER}${paths[i]}"Verify both the system and logged-in-user domains on a test Mac:
#!/bin/bash
user=$(stat -f "%Su" /dev/console)
uid=$(id -u "$user")
for label in \
"2BUA8C4S2C.com.1password.browser-helper" \
"com.1password.1password-launcher"; do
sudo launchctl print "system/$label" >/dev/null 2>&1 && echo "system: $label"
launchctl print "gui/$uid/$label" >/dev/null 2>&1 && echo "user: $label"
done🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/1password/darwin.json` at line 20, Update
remove_launchctl_service to check and remove services through explicit system
and logged-in-user GUI launchd domains rather than relying on the caller’s
default domain. Derive the user domain from LOGGED_IN_USER and its UID, and
construct user LaunchAgent paths from /Users/$LOGGED_IN_USER instead of $HOME,
while preserving the existing sudo handling for system operations.
| "03b9aece": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Cursor.app\"\nsudo rm -rf 'cursor'\ntrash $LOGGED_IN_USER '~/.cursor'\ntrash $LOGGED_IN_USER '~/.cursor-tutor'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Caches/cursor-updater'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.todesktop.230313mzl4w4u92.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Cursor'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.todesktop.*'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.todesktop.*.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.todesktop.*'\ntrash $LOGGED_IN_USER '~/Library/Logs/Cursor'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ByHost/com.todesktop.*.ShipIt.*.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.todesktop.*.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.todesktop.*.savedState'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/todesktop.com.ToDesktop-Installer.savedState'\n", | ||
| "5147ff0b": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.todesktop.230313mzl4w4u92'\nif [ -d \"$APPDIR/Cursor.app\" ]; then\n\tsudo mv \"$APPDIR/Cursor.app\" \"$TMPDIR/Cursor.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Cursor.app\" \"$APPDIR\"\nrelaunch_application 'com.todesktop.230313mzl4w4u92'\nmkdir -p .\n/bin/ln -h -f -s -- \"$APPDIR/Cursor.app/Contents/Resources/app/bin/code\" \"cursor\"\n" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Do not recursively delete a relative path as root.
Line 19 runs sudo rm -rf 'cursor'. If uninstall runs from a directory containing an unrelated cursor directory, it can delete that directory recursively; from another working directory, it will not remove the link created by the installer on Line 20. Use one absolute CLI-link path in both scripts and remove only the expected symlink with rm --.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/cursor/darwin.json` around lines 19 - 20, Update
the uninstall script’s `sudo rm -rf 'cursor'` command to target the same
absolute CLI-link path created by the installer’s `/bin/ln` command, and remove
it with `rm --` rather than recursive deletion. Ensure the installer and
uninstaller consistently reference that absolute expected symlink path.
| ], | ||
| "refs": { | ||
| "46a242eb": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nquit_application 'com.hnc.Discord'\nquit_application 'com.hnc.Discord.helper.Plugin'\nquit_application 'com.hnc.Discord.helper.Renderer'\nsudo rm -rf \"$APPDIR/Discord.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.hnc.discord.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/discord'\ntrash $LOGGED_IN_USER '~/Library/Application%20Support/discord'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.hnc.Discord'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.hnc.Discord.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/Cookies/com.hnc.Discord.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.hnc.Discord'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.hnc.Discord.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.hnc.Discord.helper.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.hnc.Discord.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.hnc.Discord.savedState'\n", | ||
| "450a6520": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.discord.discord.ShipIt'\nquit_application 'com.hnc.Discord'\nquit_application 'com.hnc.Discord.helper.Plugin'\nquit_application 'com.hnc.Discord.helper.Renderer'\nsudo rm -rf \"$APPDIR/Discord.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.hnc.discord.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/discord'\ntrash $LOGGED_IN_USER '~/Library/Application%20Support/discord'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.hnc.Discord'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.hnc.Discord.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/Cookies/com.hnc.Discord.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.hnc.Discord'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.hnc.Discord.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ByHost/com.discord.discord.ShipIt.*.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.hnc.Discord.helper.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.hnc.Discord.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.hnc.Discord.savedState'\n", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Locate target files:\n'
git ls-files 'ee/maintained-apps/outputs/*/*.json' | grep -E '/(disc ord|chatgpt-atlas)/darwin\.json$' || true
printf '\nRelevant snippets:\n'
for f in ee/maintained-apps/outputs/discord/darwin.json ee/maintained-apps/outputs/chatgpt-atlas/darwin.json; do
if [ -f "$f" ]; then
echo "--- $f"
sed -n '1,260p' "$f"
fi
done
printf '\nSearch for generated darwin uninstall targets and helper patterns:\n'
rg -n "remove_launchctl_service|launch_agent|LaunchAgent|shipit|update-helper|dar win|darwin\.json" ee/maintained-apps ee -g '*.ts' -g '*.js' -g '*.go' -g '*.json' | head -n 200Repository: fleetdm/fleet
Length of output: 1915
🌐 Web query:
Apple launchctl user launchd domain sudo /bin/launchctl remove user -l <UID> default Domain.plist
💡 Result:
The command format you mentioned, "sudo /bin/launchctl remove user default Domain.plist," is not a valid or standard command in modern macOS (macOS 10.10 and later) [1][2]. The "remove" subcommand is legacy syntax, and the management of services now relies on the "bootstrap" and "bootout" subcommands [1][3][4]. In modern macOS, you manage services by targeting specific "domains" rather than manipulating plist files directly by path [5][6]. The correct modern approach to unload a service is to use the bootout command [4]. Common and Correct Modern Syntax: 1. Identify the Domain and Service: - GUI-based services (most user-level agents) reside in the gui/<UID> domain [5][6]. - Non-GUI user services reside in the user/<UID> domain [5][6]. - System-wide services reside in the system/ domain (requires root/sudo) [5][6]. - You can find your current UID by running id -u [2][7][4]. 2. Unload (Stop) a Service: To unload a service, use the following syntax [4]: launchctl bootout <domain-target>/<service-identifier> Example (for a GUI user with UID 501): launchctl bootout gui/501/com.example.service [8][4] 3. Disable a Service Persistently: If you want to prevent a service from starting entirely (across reboots), use the disable command [7][6]: launchctl disable <domain-target>/<service-identifier> [8] Example: launchctl disable gui/501/com.example.service [8] Key Notes: - Bootout vs. Unload: bootout replaces the legacy unload command [1][4]. It requires the service identifier (the name inside the plist), not the file path [4]. - Privileges: You typically do not need sudo for gui/ or user/ domain services if you are acting on your own domain [1]. If you are managing system/ services, sudo is required [1][3][4]. - Error Handling: Unlike legacy commands, bootout and bootstrap provide clear error messages if they fail [4]. If you receive an "Input/output error," it often indicates the service is in a domain context you are not currently part of (e.g., trying to unload a GUI service from an SSH session) [9][10].
Citations:
- 1: https://ss64.com/mac/launchctl.html
- 2: https://joelsenders.wordpress.com/2019/03/14/dear-launchctl-were-all-using-you-wrong/
- 3: https://real-world-systems.com/docs/launchctl.1.html
- 4: https://osxhub.com/macos-launchctl-manage-services/
- 5: https://gist.github.com/masklinn/a532dfe55bdeab3d60ab8e46ccc38a68?permalink_comment_id=3735830
- 6: https://manp.gs/mac/1/launchctl
- 7: https://johnturner.dev/notes/launchd-macos/
- 8: https://apple.stackexchange.com/questions/471436/disabling-services-daemons-agents-with-launchctl
- 9: https://stackoverflow.com/questions/70127661/running-launchd-services-with-non-root-user-on-macos
- 10: https://thekodelab.com/en/posts/macos-gui-terminal-vs-ssh-session/
🌐 Web query:
macOS LaunchAgents path user Home Library LaunchAgents default plist launchctl remove sudo launchctl bootout user UID
💡 Result:
On macOS, LaunchAgents are service configuration files (property lists, or plists) that tell launchd to run tasks on behalf of a specific user [1][2]. The default path for user-specific LaunchAgents is: /Library/LaunchAgents For these agents, the user does not need to use sudo to manage them, as they run with the privileges of the logged-in user [3][4]. Managing LaunchAgents via launchctl The modern, preferred way to manage these services is using the bootstrap and bootout subcommands [5][6]. 1. Identify your UID You can find your current user ID (UID) by running: id -u 2. Use bootout to remove a service To stop and remove a service, use the bootout subcommand. Note that while bootstrap accepts a path, bootout requires the domain and the service label (not the file path) [5]. launchctl bootout gui/UID/label For example, if your UID is 501 and your label is com.example.myagent: launchctl bootout gui/501/com.example.myagent Key Distinctions - bootstrap vs. bootout: bootstrap targets a file path to load a service, while bootout targets a service label to unload it [7][5]. - gui/UID: This domain represents the user's graphical session. Using this domain ensures the agent runs in the correct session context [5][6]. - sudo: Generally, you should not use sudo for user LaunchAgents (/Library/LaunchAgents). sudo is typically reserved for system-wide services located in /Library/LaunchDaemons or /Library/LaunchAgents, which run under the system domain [5][4]. If you are acting on your own LaunchAgent, running command-line tools without sudo is sufficient and safer [4]. If a service is stubborn, you can use launchctl print gui/UID/label to inspect its status or use kickstart -k to force-restart it without fully unloading/loading it [5].
Citations:
- 1: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
- 2: https://support.apple.com/guide/terminal/script-management-with-launchd-apdc6c1077b-5d5d-4d35-9c19-60f2397b2369/mac
- 3: https://developer.apple.com/library/archive/technotes/tn2083/_index.html
- 4: https://ss64.com/mac/launchctl.html
- 5: https://osxhub.com/macos-launchctl-manage-services/
- 6: https://lists.macosforge.org/pipermail/launchd-dev/2015-July/001139.html
- 7: https://manp.gs/mac/1/launchctl
🌐 Web query:
macOS launchctl remove legacy remove service sudo bootout domain
💡 Result:
In modern macOS versions, the launchctl remove and unload commands are considered legacy [1][2][3]. Apple recommends using bootout for managing the removal or stopping of services [1][2]. Key differences and usage guidance: 1. Modern Syntax (Recommended): Use launchctl bootout to stop and remove a service [1][2][3]. Unlike the legacy unload command, bootout requires specifying the target domain (e.g., gui/UID, system/, or user/UID) along with the service identifier [3][4]. - Example: launchctl bootout system/com.example.service [4] - Example (for a user agent): launchctl bootout gui/$(id -u) /path/to/service.plist [3] 2. Legacy Commands: launchctl remove and unload are older methods that may still work but are generally discouraged in favor of bootout and bootstrap [1][2][5]. remove by label is particularly noted in legacy documentation as a way to remove a job, but it is not the preferred modern practice [6][7]. 3. Sudo Usage: Modern launchctl commands generally do not require sudo if you are targeting your own user session (e.g., gui/UID) [2][3]. However, sudo is required when managing system-wide services located in /Library/LaunchDaemons (targeting the system/ domain) [3][4]. In summary, for current macOS environments, prefer launchctl bootout <domain>/<service_label_or_path> over the older remove or unload commands to ensure better error reporting and adherence to current system architecture [1][3].
Citations:
- 1: https://leancrew.com/all-this/man/man1/launchctl.html
- 2: https://ss64.com/mac/launchctl.html
- 3: https://osxhub.com/macos-launchctl-manage-services/
- 4: https://apple.stackexchange.com/questions/366281/launchd-confusion-on-semantics-of-bootstrap-and-bootout-etc-after-reading-manu
- 5: https://manp.gs/mac/1/launchctl
- 6: https://www.unix.com/man_page/mojave/1/launchctl/
- 7: https://osxdaily.com/2011/03/08/remove-an-agent-from-launchd/
Run launchAgent cleanup in the console user’s launchd domain.
When the uninstaller runs as root, launchctl list/remove operates in the system/root domain and $HOME points to /root, so user LaunchAgents saved at ~/Library/LaunchAgents can remain installed. Find the console user’s UID and home directory, target that user’s gui/<uid> launchd domain for the jobs, and delete the user plist from that home directory instead.
ee/maintained-apps/outputs/discord/darwin.json#L19-<tail>: apply this tocom.discord.discord.ShipIt.ee/maintained-apps/outputs/chatgpt-atlas/darwin.json#L19-<tail>: apply this tocom.openai.atlas.update-helper.
📍 Affects 2 files
ee/maintained-apps/outputs/discord/darwin.json#L19-L19(this comment)ee/maintained-apps/outputs/chatgpt-atlas/darwin.json#L19-L19
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/discord/darwin.json` at line 19, The launchAgent
cleanup in remove_launchctl_service currently uses the root launchd domain and
/root when run as root. In ee/maintained-apps/outputs/discord/darwin.json:19-19,
update cleanup for com.discord.discord.ShipIt to resolve the console user’s UID
and home directory, run launchctl list/remove against gui/<uid>, and remove the
plist from that user’s home LaunchAgents directory; apply the same change to
com.openai.atlas.update-helper in
ee/maintained-apps/outputs/chatgpt-atlas/darwin.json:19-19.
| "214a13cd": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.elgato.StreamDeck'\nsudo installer -pkg \"$TMPDIR/Stream_Deck_7.5.0.22885.pkg\" -target /\nrelaunch_application 'com.elgato.StreamDeck'\n", | ||
| "b842b140": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.elgato.StreamDeck*'\nquit_application 'com.elgato.StreamDeck'\nremove_pkg_files 'com.elgato.StreamDeck'\nforget_pkg 'com.elgato.StreamDeck'\nsudo rm -rf '/Applications/Elgato Stream Deck.app'\nsudo rm -rf '/Library/LaunchAgents/com.elgato.StreamDeck.plist'\nsudo rm -rf '~/Library/LaunchAgents/com.elgato.StreamDeck.plist'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.elgato.StreamDeck'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.elgato.StreamDeck'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.elgato.StreamDeck'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.elgato.StreamDeck.plist'\n" | ||
| "81223e72": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.elgato.StreamDeck'\nsudo installer -pkg \"$TMPDIR/Stream_Deck_7.5.1.22901.pkg\" -target /\nrelaunch_application 'com.elgato.StreamDeck'\n", | ||
| "aff3ed62": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.elgato.StreamDeck*'\nremove_launchctl_service 'com.elgato.StreamDeck.trampoline'\nquit_application 'com.elgato.StreamDeck'\nremove_pkg_files 'com.elgato.StreamDeck'\nforget_pkg 'com.elgato.StreamDeck'\nsudo rm -rf '/Applications/Elgato Stream Deck.app'\nsudo rm -rf '/Library/LaunchAgents/com.elgato.StreamDeck.plist'\nsudo rm -rf '~/Library/LaunchAgents/com.elgato.StreamDeck.plist'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.elgato.StreamDeck'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.elgato.StreamDeck'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.elgato.StreamDeck'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.elgato.StreamDeck.plist'\n" |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Preserve cleanup for unloaded launch services.
remove_launchctl_service 'com.elgato.StreamDeck*' returns before deleting plist paths when no matching service is loaded. After removing the explicit com.elgato.StreamDeck.trampoline call, a stale trampoline plist can remain; the quoted ~/Library/... command does not provide a working fallback. Restore the explicit cleanup or change the helper to remove matching plist files even when services are unloaded.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/elgato-stream-deck/darwin.json` at line 20, Update
remove_launchctl_service so wildcard patterns still remove matching plist files
when no matching launchctl service is loaded; do not return before the
path-cleanup loops. Preserve the explicit service handling and ensure the stale
com.elgato.StreamDeck.trampoline plist is cleaned up, since the quoted ~/Library
fallback is ineffective.
| "5fe54a7b": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nquit_application 'com.figma.agent'\nsudo rm -rf \"$APPDIR/Figma.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/Figma'\ntrash $LOGGED_IN_USER '~/Library/Application Support/figma-desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.figma.agent'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.figma.Desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.figma.Desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.figma.Desktop.savedState'\n", | ||
| "f0952230": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.figma.Desktop'\nif [ -d \"$APPDIR/Figma.app\" ]; then\n\tsudo mv \"$APPDIR/Figma.app\" \"$TMPDIR/Figma.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Figma.app\" \"$APPDIR\"\nrelaunch_application 'com.figma.Desktop'\n" | ||
| "f0952230": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.figma.Desktop'\nif [ -d \"$APPDIR/Figma.app\" ]; then\n\tsudo mv \"$APPDIR/Figma.app\" \"$TMPDIR/Figma.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Figma.app\" \"$APPDIR\"\nrelaunch_application 'com.figma.Desktop'\n", | ||
| "ffdf9bc3": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nquit_application 'com.figma.agent'\nsudo rm -rf \"$APPDIR/Figma.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.figma.desktop.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Figma'\ntrash $LOGGED_IN_USER '~/Library/Application Support/figma-desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.figma.agent'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.figma.Desktop'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.figma.agent'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.figma.Desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.figma.Desktop.savedState'\n" |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate figma files =="
git ls-files | rg '(^|/)figma/|manifest|darwin\.json|package|apps|maintained-apps' | sed -n '1,200p'
echo
echo "== relevant figma files =="
fd -d 3 -a '.*' . | rg 'figma' || true
echo
echo "== search Figma references =="
rg -n "Figma|figma|application id|quit_application|com\.figma|manifest|bundle_id|bundleIdentifier" -S . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | sed -n '1,240p'Repository: fleetdm/fleet
Length of output: 1915
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repo files present? =="
pwd
git rev-parse --show-toplevel || true
git status --short || true
git ls-files ee/maintained-apps 'figma*' -z 2>/dev/null | tr '\0' '\n' | sed -n '1,200p' || true
echo
echo "== targeted location =="
if [ -f ee/maintained-apps/outputs/figma/darwin.json ]; then
wc -l ee/maintained-apps/outputs/figma/darwin.json
sed -n '1,40p' ee/maintained-apps/outputs/figma/darwin.json
else
fd -a 'darwin\.json|manifest|README' . | sed -n '1,120p' || true
fi
echo
echo "== focused references with bounded output =="
rg -n "com\.figma|Figma|figma|quit_application|application id|bundle_id|bundleIdentifier|manifest" ee/maintained-apps outputs packages apps 2>/dev/null | sed -n '1,240p' || trueRepository: fleetdm/fleet
Length of output: 1915
🌐 Web query:
Figma macOS application bundle identifier com.figma.Desktop com.figma.agent
💡 Result:
The macOS bundle identifiers for Figma are as follows: - com.figma.Desktop: This is the bundle identifier for the main Figma desktop application [1][2]. It is used for system configurations, such as managing property list settings (e.g., via the defaults command) [1], and is the standard identifier used by device management and security tools [3][4]. - com.figma.agent: This is the bundle identifier for the Figma Agent (also referred to as FigmaAgent) [5][6]. The Figma Agent is a background utility that automatically detects local fonts and makes them available within the Figma application [7][8]. It operates as a background service and is often associated with Login Items and Launch Agents on macOS [9][6][8]. While the main application identifier (com.figma.Desktop) is public and stable [1][10], the Figma Agent (com.figma.agent) is a supplementary process [7]. Users or administrators managing these applications may need to interact with both identifiers when configuring permissions, startup items, or cleanup scripts [5][11][4][6].
Citations:
- 1: https://help.figma.com/hc/en-us/articles/17719332934167-Configure-desktop-app-settings-via-a-property-list-on-macOS
- 2: https://doesitarm.com/app/figma
- 3: https://appcatalog.cloud/apps/figma
- 4: https://fleetdm.com/app-library/figma
- 5: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/f/figma-agent.rb
- 6: https://community.latenode.com/t/stop-figma-agent-from-automatically-adding-itself-to-startup-items-on-mac/23639
- 7: https://help.figma.com/hc/en-us/articles/5601429983767-Guide-to-the-Figma-desktop-app
- 8: https://forum.figma.com/suggest-a-feature-11/stop-automatically-adding-figmaagent-to-login-items-10434?fid=11&tid=10434
- 9: https://desktop.figma.com/agent/mac/uninstall.sh
- 10: https://macupdater.com/app_updates/appinfo/com.figma.Desktop/index.html
- 11: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/f/figma.rb
Quit the managed Figma application, not only its agent.
The uninstall cleans up Figma.app and com.figma.Desktop data, but only quits com.figma.agent. Quit com.figma.Desktop too so rm -rf "$APPDIR/Figma.app" does not try to remove the app while the main Figma process is still running.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/figma/darwin.json` at line 20, Update the
uninstall sequence around quit_application to also quit the managed Figma
desktop bundle ID, com.figma.Desktop, before removing Figma.app; retain the
existing com.figma.agent shutdown and cleanup behavior.
| "uninstall_script_ref": "292c5733", | ||
| "sha256": "a90d1dd5c5cad5fdae375968a39149fd337574834bdd9cdaef9ef7be9bc203b0", | ||
| "default_categories": [ | ||
| "Browsers" | ||
| ] | ||
| } | ||
| ], | ||
| "refs": { | ||
| "a313f903": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'org.mozilla.firefoxdeveloperedition'\nif [ -d \"$APPDIR/Firefox Developer Edition.app\" ]; then\n\tsudo mv \"$APPDIR/Firefox Developer Edition.app\" \"$TMPDIR/Firefox Developer Edition.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Firefox Developer Edition.app\" \"$APPDIR\"\nrelaunch_application 'org.mozilla.firefoxdeveloperedition'\n", | ||
| "b108b0ff": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Firefox Developer Edition.app\"\nsudo rmdir '~/Library/Application Support/Mozilla'\nsudo rmdir '~/Library/Caches/Mozilla'\nsudo rmdir '~/Library/Caches/Mozilla/updates'\nsudo rmdir '~/Library/Caches/Mozilla/updates/Applications'\ntrash $LOGGED_IN_USER '/Library/Logs/DiagnosticReports/firefox_*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.mozilla.firefox.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/CrashReporter/firefox_*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Firefox'\ntrash $LOGGED_IN_USER '~/Library/Caches/Firefox'\ntrash $LOGGED_IN_USER '~/Library/Caches/Mozilla/updates/Applications/Firefox'\ntrash $LOGGED_IN_USER '~/Library/Caches/org.mozilla.firefox'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.mozilla.firefox.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.mozilla.firefox.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/org.mozilla.firefox'\n" | ||
| "292c5733": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Firefox Developer Edition.app\"\nsudo rmdir '~/Library/Application Support/Mozilla'\nsudo rmdir '~/Library/Caches/Mozilla'\nsudo rmdir '~/Library/Caches/Mozilla/updates'\nsudo rmdir '~/Library/Caches/Mozilla/updates/Applications'\ntrash $LOGGED_IN_USER '/Library/Logs/DiagnosticReports/firefox_*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.mozilla.firefox.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/CrashReporter/firefox_*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Firefox'\ntrash $LOGGED_IN_USER '~/Library/Caches/Firefox'\ntrash $LOGGED_IN_USER '~/Library/Caches/Mozilla/updates/Applications/Firefox'\ntrash $LOGGED_IN_USER '~/Library/Caches/org.mozilla.firefox'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.mozilla.firefox.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.mozilla.firefoxdeveloperedition.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.mozilla.firefox.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/org.mozilla.firefox'\n", |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Do not remove regular Firefox data when uninstalling Developer Edition.
The manifest identifies this app as org.mozilla.firefoxdeveloperedition, but the new script trashes regular Firefox paths and identifiers, including ~/Library/Application Support/Firefox and org.mozilla.firefox state. On systems with both products installed, this can remove the regular Firefox profile during Developer Edition uninstall. Scope cleanup to Developer Edition-specific paths.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/firefox`@developer-edition/darwin.json around
lines 11 - 19, Update uninstall script ref 292c5733 to remove only Firefox
Developer Edition data, replacing regular Firefox paths and identifiers such as
~/Library/Application Support/Firefox, org.mozilla.firefox, and firefox_* with
their Developer Edition-specific equivalents matching
org.mozilla.firefoxdeveloperedition. Preserve cleanup of shared Mozilla
directories only where it cannot affect regular Firefox data.
| "version": "7.0", | ||
| "queries": { | ||
| "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'app.kaleidoscope.v6';", | ||
| "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'app.kaleidoscope.v6' AND version_compare(bundle_short_version, '6.7') < 0);" | ||
| "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'app.kaleidoscope.v6' AND version_compare(bundle_short_version, '7.0') < 0);" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate kaleidoscope files =="
fd -i 'kaleidoscope|kaleidoscope' . || true
echo
echo "== target darwin.json relevant lines =="
if [ -f ee/maintained-apps/outputs/kaleidoscope/darwin.json ]; then
cat -n ee/maintained-apps/outputs/kaleidoscope/darwin.json
fi
echo
echo "== inspect installed app identifiers/scripts =="
for f in $(fd -i 'kaleidoscope.*\.(sh|json|yaml|yml)$' ee/maintained-apps/outputs 2>/dev/null || true); do
echo "--- $f"
rg -n "app\.kaleidoscope\.(v6|v7)|kaleidoscope|bundle_identifier|identify|quitall|quit" "$f" || true
done
echo
echo "== broader bundle id search =="
rg -n "app\.kaleidoscope\.(v6|v7)|kaleidoscope\.v6|kaleidoscope\.v7" .Repository: fleetdm/fleet
Length of output: 1915
🌐 Web query:
Kaleidoscope.app CFBundleIdentifier app.kaleidoscope.v6 app.kaleidoscope.v7
💡 Result:
The Kaleidoscope app uses version-specific CFBundleIdentifiers for its major releases to allow multiple versions to coexist on the same system. The identifiers app.kaleidoscope.v6 and app.kaleidoscope.v7 are the official CFBundleIdentifiers for Kaleidoscope version 6 and version 7, respectively [1][2]. Earlier versions of the application utilized different identifier schemes, such as app.kaleidoscope.v4 for version 4 [3] and com.blackpixel.kaleidoscope for older releases managed by the previous developer, Black Pixel [4]. These bundle identifiers are essential for macOS management, as they are used by system tools for configuration, installation, and uninstallation, as well as for defining application-specific paths in the Library folder (e.g., Application Support, Caches, and Saved Application State) [1][2].
Citations:
- 1: https://fleetdm.com/software-catalog/kaleidoscope-darwin
- 2: https://github.com/Homebrew/homebrew-cask/blob/7ab5ddf8fd0fc54e2361f87ae0c288a17481510d/Casks/k/kaleidoscope.rb
- 3: https://appcatalog.cloud/apps/kaleidoscope
- 4: https://en.freedownloadmanager.org/Mac-OS/Kaleidoscope.html
Align the Kaleidoscope operations with the 7.0 bundle identifier.
Kaleidoscope 7 uses app.kaleidoscope.v7, while this package still queries and quits/installer-relaunches app.kaleidoscope.v6. Update the detection queries, installer, and uninstallant scripts to target app.kaleidoscope.v7 consistently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/kaleidoscope/darwin.json` around lines 4 - 7,
Update the Kaleidoscope package’s detection queries and all related installer,
quit, relaunch, and uninstallant references from app.kaleidoscope.v6 to
app.kaleidoscope.v7, while preserving the existing version checks and operation
flow.
| "refs": { | ||
| "3a2f038c": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.nordvpn.macos.teams'\nsudo installer -pkg \"$TMPDIR/NordLayer_v3.11.0.pkg\" -target /\nrelaunch_application 'com.nordvpn.macos.teams'\n", | ||
| "97f61740": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.nordvpn.macos.teams'\nremove_launchctl_service 'com.nordvpn.macos.teams.assistant'\nremove_launchctl_service 'com.nordvpn.macos.teams.helper'\nquit_application 'com.nordvpn.macos.teams'\nremove_pkg_files 'com.nordvpn.macos.teams'\nforget_pkg 'com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.nordvpn.macos.teams.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.nordvpn.macos.teams.plist'\n" | ||
| "4ab665bb": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.nordvpn.macos.teams'\nremove_launchctl_service 'com.nordvpn.macos.teams.assistant'\nremove_launchctl_service 'com.nordvpn.macos.teams.helper'\nquit_application 'com.nordvpn.macos.teams'\nremove_pkg_files 'com.nordvpn.macos.teams'\nforget_pkg 'com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/group.com.nordlayer.macos'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.nordvpn.macos.teams.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/group.com.nordlayer.macos'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.nordvpn.macos.teams'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.nordvpn.macos.teams.plist'\n" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg '(^|/)darwi.*\.json$|nordlayer' || true
echo
echo "Target file snippets:"
if [ -f ee/maintained-apps/outputs/nordlayer/darwin.json ]; then
nl -ba ee/maintained-apps/outputs/nordlayer/darwin.json | sed -n '1,80p'
fi
echo
echo "Occurrences of console user and LOGGED_IN_USER in context:"
rg -n "ConsoleUser|console_user|LOGGED_IN_USER|quitting application|remove_launchctl_service|quit_application|remove_pkg_files|forget_pkg|trash" .Repository: fleetdm/fleet
Length of output: 1915
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "PWD:"
pwd
echo "Top-level entries:"
ls -la | sed -n '1,80p'
echo "Candidate files:"
git ls-files | rg '(^|/)darwi.*\.json$|nordlayer' || true
echo
echo "Target file snippets:"
if [ -f ee/maintained-apps/outputs/nordlayer/darwin.json ]; then
nl -ba ee/maintained-apps/outputs/nordlayer/darwin.json | sed -n '1,90p'
fi
echo
echo "Occurrences of console user and LOGGED_IN_USER in context:"
rg -n "ConsoleUser|console_user|LOGGED_IN_USER|quitting application|remove_launchctl_service|quit_application|remove_pkg_files|forget_pkg|trash" . || trueRepository: fleetdm/fleet
Length of output: 1915
Guard user-specific cleanup when no console user is available.
LOGGED_IN_USER is populated from State:/Users/ConsoleUser; during unattended installation it can be empty, root, or loginwindow. Skipping the subsequent trash calls when it is invalid, and quoting $LOGGED_IN_USER, prevents malformed cleanup commands and avoids leaving user-scoped data behind.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/nordlayer/darwin.json` at line 20, Validate
LOGGED_IN_USER after it is populated, and only execute the subsequent
user-specific trash calls when it is non-empty and not root or loginwindow.
Quote the LOGGED_IN_USER argument at each trash invocation, preserving the
existing cleanup behavior for valid console users.
| ], | ||
| "refs": { | ||
| "20e49d94": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TablePlus.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.tinyapp.TablePlus'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tinyapp.TablePlus'\ntrash $LOGGED_IN_USER '~/Library/Cookies/com.tinyapp.TablePlus.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tinyapp.TablePlus.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.tinyapp.TablePlus.savedState'\n", | ||
| "19abdcd7": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TablePlus.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.tinyapp.tableplus.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.tinyapp.TablePlus'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tinyapp.TablePlus'\ntrash $LOGGED_IN_USER '~/Library/Cookies/com.tinyapp.TablePlus.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.tinyapp.TablePlus'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tinyapp.TablePlus.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.tinyapp.TablePlus.savedState'\n", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## Candidate files"
fd -a 'darwin\.json$' . | sed 's#^\./##' | grep 'tableplus/darwin.json' || true
echo "## Relevant tableplus darwin.json"
if [ -f ee/maintained-apps/outputs/tableplus/darwin.json ]; then
wc -l ee/maintained-apps/outputs/tableplus/darwin.json
cat -n ee/maintained-apps/outputs/tableplus/darwin.json
fi
echo "## Occurrences of tableplus identifiers in maintained-apps outputs"
rg -n "microapp|TablePlus|tableplus|sfl|SFL|sharedfilelist" ee/maintained-apps/outputs/tableplus ee/maintained-apps 2>/dev/null | head -200 || trueRepository: fleetdm/fleet
Length of output: 1915
🌐 Web query:
TablePlus macOS bundle identifier com.tinyapp.TablePlus ApplicationRecentDocuments sfl file
💡 Result:
The macOS application bundle identifier for TablePlus is com.tinyapp.TablePlus [1][2][3]. Regarding the.sfl files you mentioned: these are Shared File List files managed by the macOS system service sharedfilelistd [4]. In macOS, applications that utilize standard AppKit document management (via NSDocumentController) delegate the tracking of "Recent Documents" to the operating system [5]. Specifically: 1. Storage Location: Recent documents for applications are stored in a system-managed directory at ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/ [4][6][5]. 2. File Format: For TablePlus, macOS maintains a file named com.tinyapp.TablePlus.sfl (or a variant like.sfl2) within that directory [4][7]. 3. Purpose: These.sfl files are binary property lists that store bookmarks to recently opened documents, which the system uses to populate the Open Recent menu in the application's File menu [4][7][5]. Because these files are maintained by the system service sharedfilelistd, they are not intended to be managed or edited directly by users or the application itself [5]. Changes to the Recent Items list are handled automatically by macOS when the application opens or interacts with files [4]. Do not attempt to manually modify these files, as they are system-protected and may cause issues with the application's ability to track recent files correctly [4][5].
Citations:
- 1: https://appcatalog.cloud/apps/tableplus
- 2: [Bug] App crashes when connecting to a Oracle 12c database TablePlus/TablePlus#3767
- 3: https://macupdater.com/app_updates/appinfo/com.tinyapp.TablePlus/index.html
- 4: https://eclecticlight.co/2017/08/10/recent-items-launch-services-and-sharedfilelists/
- 5: https://apple.stackexchange.com/questions/464860/where-does-pages-store-its-list-of-recently-opened-documents
- 6: https://forum.latenightsw.com/t/how-do-i-get-recent-files-of-all-apps/1299
- 7: https://eclecticlight.co/2019/03/18/how-launchservices-builds-the-open-recent-menu-and-outsmarts-aliases/
Keep the shared-file-list cleanup case-sensitive.
macOS records TablePlus recent documents as com.tinyapp.TablePlus.sfl*; com.tinyapp.tableplus.sfl* will not match on a case-sensitive volume. Use the exact bundle-identifier filename.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/tableplus/darwin.json` at line 19, Update the
shared-file-list cleanup argument in the script to use the exact case-sensitive
filename prefix com.tinyapp.TablePlus.sfl*. Leave the trash function and other
cleanup paths unchanged.
Automated ingestion of latest Fleet-maintained app data.
Summary by CodeRabbit
New Features
Bug Fixes