Update Fleet-maintained apps - #50113
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.Y22HL4 2026-07-29 02:56:32.577052658 +0000
+++ /tmp/new.Xktj8N 2026-07-29 02:56:32.577052658 +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.BFHxgi 2026-07-29 02:56:32.634053800 +0000
+++ /tmp/new.YcsgeR 2026-07-29 02:56:32.634053800 +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.vwmZhW 2026-07-29 02:56:32.792056965 +0000
+++ /tmp/new.NYqgmG 2026-07-29 02:56:32.792056965 +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.kFrMSm 2026-07-29 02:56:32.968060492 +0000
+++ /tmp/new.Pswp3V 2026-07-29 02:56:32.968060492 +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.JMceRT 2026-07-29 02:56:33.107063277 +0000
+++ /tmp/new.ZmW7lA 2026-07-29 02:56:33.107063277 +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.WLYTFD 2026-07-29 02:56:33.249066122 +0000
+++ /tmp/new.Lcxtpl 2026-07-29 02:56:33.249066122 +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.EIRcpj 2026-07-29 02:56:33.467070490 +0000
+++ /tmp/new.Q4ejKg 2026-07-29 02:56:33.468070510 +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.d4xGi0 2026-07-29 02:56:33.600073155 +0000
+++ /tmp/new.cTwOQi 2026-07-29 02:56:33.600073155 +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.9mYL7f 2026-07-29 02:56:33.619073536 +0000
+++ /tmp/new.qMRKt7 2026-07-29 02:56:33.619073536 +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.41pymD 2026-07-29 02:56:33.788076922 +0000
+++ /tmp/new.DodP3V 2026-07-29 02:56:33.788076922 +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.tbU1fs 2026-07-29 02:56:33.945080067 +0000
+++ /tmp/new.0vZpAJ 2026-07-29 02:56:33.945080067 +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.dT1iN6 2026-07-29 02:56:34.121083594 +0000
+++ /tmp/new.n7oc8z 2026-07-29 02:56:34.121083594 +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.389znz 2026-07-29 02:56:34.252086219 +0000
+++ /tmp/new.4Vp4Wa 2026-07-29 02:56:34.252086219 +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.OfDRKt 2026-07-29 02:56:34.301087200 +0000
+++ /tmp/new.RktXpT 2026-07-29 02:56:34.302087220 +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.InF7n7 2026-07-29 02:56:34.415089484 +0000
+++ /tmp/new.mPZRCK 2026-07-29 02:56:34.415089484 +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.fNKZII 2026-07-29 02:56:34.537091929 +0000
+++ /tmp/new.PtxDLU 2026-07-29 02:56:34.537091929 +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.zXiwtX 2026-07-29 02:56:34.691095015 +0000
+++ /tmp/new.5zUK6p 2026-07-29 02:56:34.691095015 +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.lKowW1 2026-07-29 02:56:34.853098261 +0000
+++ /tmp/new.xKGvLR 2026-07-29 02:56:34.854098281 +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.LvcRJp 2026-07-29 02:56:34.923099663 +0000
+++ /tmp/new.xyQfbt 2026-07-29 02:56:34.923099663 +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.5WydIX 2026-07-29 02:56:34.985100905 +0000
+++ /tmp/new.BQGCSJ 2026-07-29 02:56:34.985100905 +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.Ai3HiU 2026-07-29 02:56:35.041102027 +0000
+++ /tmp/new.WXluJ6 2026-07-29 02:56:35.041102027 +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.fWFDH4 2026-07-29 02:56:35.105103310 +0000
+++ /tmp/new.KH6Xla 2026-07-29 02:56:35.106103330 +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.fyIul4 2026-07-29 02:56:35.167104552 +0000
+++ /tmp/new.0t1KlF 2026-07-29 02:56:35.167104552 +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.xeeJzX 2026-07-29 02:56:35.281106836 +0000
+++ /tmp/new.500WSd 2026-07-29 02:56:35.282106856 +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.KlKTrQ 2026-07-29 02:56:35.389109000 +0000
+++ /tmp/new.e0lt7w 2026-07-29 02:56:35.389109000 +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.JddezQ 2026-07-29 02:56:35.619113608 +0000
+++ /tmp/new.9Cpg2P 2026-07-29 02:56:35.619113608 +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.24wie7 2026-07-29 02:56:35.950120240 +0000
+++ /tmp/new.bQDxY1 2026-07-29 02:56:35.950120240 +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.hmrP0n 2026-07-29 02:56:36.003121302 +0000
+++ /tmp/new.0lYaHM 2026-07-29 02:56:36.004121322 +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.qWf7ff 2026-07-29 02:56:36.100123246 +0000
+++ /tmp/new.lVD9sJ 2026-07-29 02:56:36.100123246 +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.KBke94 2026-07-29 02:56:36.536131982 +0000
+++ /tmp/new.dsnQZh 2026-07-29 02:56:36.536131982 +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) === |
WalkthroughUpdated maintained-app definitions across macOS and Windows with newer versions, detection thresholds, installer URLs, and checksums. Several entries now reference revised installer or uninstaller scripts. The script changes update package filenames, launchctl service cleanup, application bundle identifiers, Trash targets, Windows MSI product codes, and missing-uninstaller exit behavior. Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ee/maintained-apps/outputs/etrecheckpro/darwin.json (1)
4-12: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftPinned versions must use immutable installer artifacts.
These manifests advertise specific versions but point downstream installers at generic URLs and disable checksum validation with
no_check. If the source URL changes or a 304 is reused, the “pinned” package can drift from the advertised version.
ee/maintained-apps/outputs/etrecheckpro/darwin.json: use a versioned/unmodifiable installer artifact for6.8.16and provide its SHA256.ee/maintained-apps/outputs/whatsapp/darwin.json: do the same for26.30.16or stop publishing this as a pinned version.🤖 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/etrecheckpro/darwin.json` around lines 4 - 12, Replace the generic installer URL and “no_check” checksum in ee/maintained-apps/outputs/etrecheckpro/darwin.json (lines 4-12) with an immutable artifact for version 6.8.16 and its verified SHA256. Apply the same change in ee/maintained-apps/outputs/whatsapp/darwin.json (lines 4-12) for version 26.30.16, or remove its pinned-version publication.
🤖 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 resolve LOGGED_IN_USER’s UID and
home explicitly, rather than relying on the process domain or $HOME. Run
user-agent launchctl operations in that console user’s domain, while handling
system daemons separately with the appropriate privileged domain, and build user
plist paths from the resolved console-user home so root-managed execution cleans
up the correct services and files.
In `@ee/maintained-apps/outputs/cursor/darwin.json`:
- Around line 19-20: Update the installer’s final symlink creation and the
uninstaller’s `sudo rm -rf 'cursor'` cleanup to use the same fixed absolute shim
path, rather than the current working directory. Ensure both `ln` creation and
removal target that stable location consistently, without affecting the
application bundle handling.
In `@ee/maintained-apps/outputs/elgato-stream-deck/darwin.json`:
- Line 20: Update remove_launchctl_service and its Stream Deck call sites to
target LOGGED_IN_USER’s launchd session explicitly rather than the current/root
process domain. Use the console user’s home directory for non-system plist
paths, and invoke launchctl removal in that user’s domain while retaining sudo
for system-level services and plist cleanup.
In `@ee/maintained-apps/outputs/firefox`@developer-edition/darwin.json:
- Line 19: Update the four rmdir commands in the uninstall script to replace
single-quoted paths beginning with ~ with double-quoted paths rooted at
/Users/$LOGGED_IN_USER. Preserve the existing subpaths for Application
Support/Mozilla and the Mozilla cache directories while using the resolved
logged-in user home.
In `@ee/maintained-apps/outputs/kaleidoscope/darwin.json`:
- Around line 4-7: Update the Kaleidoscope v6 bundle identifier references in
the installer and detection flow to use app.kaleidoscope.v7 consistently with
the version 7.0 payload, including the quit/relaunch commands. If this payload
is intentionally for v6, instead align all version and bundle-identifier
references to v6.
In `@ee/maintained-apps/outputs/nextcloud/darwin.json`:
- Line 20: Propagate critical installer failures before relaunching: in
ee/maintained-apps/outputs/nextcloud/darwin.json at line 20, capture and
validate the sudo installer command status before calling relaunch_application;
in ee/maintained-apps/outputs/chatgpt-atlas/darwin.json at line 20 and
ee/maintained-apps/outputs/opencode-desktop/darwin.json at line 19, validate DMG
extraction and application copy command statuses before relaunching, ensuring
failures are reported and returned rather than allowing the payload to succeed.
In `@ee/maintained-apps/outputs/opencode-desktop/darwin.json`:
- Line 20: Restore the recent-documents cleanup call in the uninstaller by
adding the ai.opencode.desktop.sfl* target to the sequence of trash calls after
the main application-support cleanup. Preserve the existing trash function’s
glob handling so all matching recent-document files are removed.
In `@ee/maintained-apps/outputs/rightfont/darwin.json`:
- Around line 4-7: Pin the installer artifacts and replace sha256: no_check with
verified checksums so Fleet can validate the advertised versions. Update
ee/maintained-apps/outputs/rightfont/darwin.json for immutable version 10.1.1
artifacts and ee/maintained-apps/outputs/roboform/darwin.json for immutable
version 9.9.5 artifacts, or implement equivalent pre-publication build
verification in each manifest’s artifact configuration.
In `@ee/maintained-apps/outputs/spyder/windows.json`:
- Line 19: Update the uninstall flow around $uninstallKeys, $foundUninstaller,
and the “not found” branch so a missing matching registry entry is not reported
as successful without independently confirming Spyder is absent. Preserve
successful exit only when the app is verified absent or the uninstaller
completes successfully; otherwise stop suppressing or propagate registry lookup
errors and return a failure status.
---
Outside diff comments:
In `@ee/maintained-apps/outputs/etrecheckpro/darwin.json`:
- Around line 4-12: Replace the generic installer URL and “no_check” checksum in
ee/maintained-apps/outputs/etrecheckpro/darwin.json (lines 4-12) with an
immutable artifact for version 6.8.16 and its verified SHA256. Apply the same
change in ee/maintained-apps/outputs/whatsapp/darwin.json (lines 4-12) for
version 26.30.16, or remove its pinned-version publication.
🪄 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: f11d8e59-81cc-43f1-8a33-8b59c5404956
📒 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
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the referenced file around the reported lines and any platform outputs.
if [ -f ee/maintained-apps/outputs/1password/darwin.json ]; then
echo "### Darwin output line count and relevant script"
wc -l ee/maintained-apps/outputs/1password/darwin.json
python3 - <<'PY'
import json
p='ee/maintained-apps/outputs/1password/darwin.json'
data=json.load(open(p, encoding='utf-8'))
for k,v in data.items():
if any(s in k for s in ['remove','uninstall','uninstall']):
print(k)
print("key with reported hash:", "a642a51c" in data)
print(data.get("a642a51c", "")[:800])
print("...")
print(data.get("a642a51c", "")[-800:])
PY
else
echo "missing ee/maintained-apps/outputs/1password/darwin.json"
fi
echo "### All files mentioning this bundle ID or launchctl cleanup"
rg -n "2BUA8C4S2C|com\.1password|remove_launchctl_service|launchctl list|launchctl remove|com\.1password\.1password-launcher|1password-launcher" ee/maintained-apps/outputs/1password || trueRepository: fleetdm/fleet
Length of output: 10158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read-only behavioral probe mirroring the bash script's console-user detection and launchctl path selection.
# It uses the sandbox's real processes/environment only to demonstrate logic ordering, not repository behavior.
python3 - <<'PY'
import os, subprocess, json, re, tempfile, sys
script = json.load(open('ee/maintained-apps/outputs/1password/darwin.json', encoding='utf-8'))['a642a51c']
print('contains scutil lookup:', 'scutil <<< "show State:/Users/ConsoleUser"' in script)
print('contains sudo launchctl:', 'sudo launchctl remove' in script)
print('contains launchctl remove without sudo:', 'launchctl remove' in script and 'sudo' not in script.split('launchctl remove')[0].split('\n')[-1] if 'launchctl remove' in script else False)
# Show domain-specific behavior for a non-lightweight/non-standard label under an elevated caller.
result = subprocess.run(['launchctl', 'list', 'com.unknown.1password.example.label'], text=True)
print('launchctl list unknown root-level label exit code:', result.returncode)
print('launchctl list unknown root-level label stdout lines (repr):', repr(result.stdout))
# Show user home resolution.
print('process HOME:', os.environ.get('HOME', '<unset>'))
PYRepository: fleetdm/fleet
Length of output: 245
Run launchctl cleanup in the console user’s domain.
remove_launchctl_service uses the process’s current launchctl domain and $HOME, while the rest of the uninstall resolves paths via LOGGED_IN_USER. Under a root-managed uninstall, this can operate in root’s launchctl domain and delete paths under /var/root/Library/LaunchAgents, leaving the console user’s 1Password services and plists behind. Resolve the console user’s UID/home explicitly and handle user versus system domains separately.
🤖 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 resolve LOGGED_IN_USER’s UID and home explicitly,
rather than relying on the process domain or $HOME. Run user-agent launchctl
operations in that console user’s domain, while handling system daemons
separately with the appropriate privileged domain, and build user plist paths
from the resolved console-user home so root-managed execution cleans up the
correct services and files.
| "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
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg 'ee/maintained-apps/outputs/cursor|maintained-apps|cursor.*\.json|cursor'
echo
echo "Target file context:"
if [ -f ee/maintained-apps/outputs/cursor/darwin.json ]; then
wc -l ee/maintained-apps/outputs/cursor/darwin.json
sed -n '1,80p' ee/maintained-apps/outputs/cursor/darwin.json
fi
echo
echo "Search for cursor outputs and path references:"
rg -n '"cursor"|cursor\.json|Cursor\.app/Contents/Resources/app/bin/code|/usr/local/|/opt/|'\''cursor'\''|sudo rm -rf|/bin/ln -h|/bin/ln -sf' -S . | head -n 200Repository: fleetdm/fleet
Length of output: 50370
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Cursor output files:"
find ee/maintained-apps/outputs/cursor -maxdepth 3 -type f -print | sort
echo
echo "cursor output filenames and relative script mentions:"
for f in ee/maintained-apps/outputs/cursor/*; do
[ -f "$f" ] || continue
echo "--- $f"
rg -n "cursor|rm -rf|rm -f|mkdir|ln -h|/usr/local|/opt|sudo " "$f" || true
done
echo
echo "Relevant shell behavior probe:"
python3 - <<'PY'
import subprocess, tempfile, pathlib, os
cases = [
(
"installer_pwd_uninstall_pwd_different_cwd",
"/tmp/uninstall_working_dir",
(
"pwd=$PWD\n"
"mkdir -p appdir\n"
"/bin/ln -h -f -s -- appdir/Cursor.app/Contents/Resources/app/bin/code cursor\n"
"printf '%s\\n' \"installed: $(pwd)/cursor\" > /tmp/created_by_installer.txt\n"
),
(
"printf '%s\\n' \"uninstaller cwd before: $(pwd)\" > /tmp/uninstaller_cwd_before.txt\n"
"pwd=$(pwd)\n"
"sudo rm -rf 'cursor'\n"
"printf '%s\\n' \"uninstalled: $(pwd)\" > /tmp/uninstaller_cwd_after.txt\n"
"if [ -e cursor ]; then printf existing\\n > /tmp/shim_state.txt; else printf removed\\n > /tmp/shim_state.txt; fi\n"
),
),
(
"installer_pwd_uninstall_pwd_matching_cwd",
"/tmp/matching_working_dir",
(
"mkdir -p appdir\n"
"/bin/ln -h -f -s -- appdir/Cursor.app/Contents/Resources/app/bin/code cursor\n"
"printf '%s\\n' \"installed: $(pwd)/cursor\" > /tmp/created_by_installer.txt\n"
),
(
"printf '%s\\n' \"uninstaller cwd before: $(pwd)\" > /tmp/uninstaller_cwd_before.txt\n"
"sudo rm -rf 'cursor'\n"
"printf '%s\\n' \"uninstalled: $(pwd)\" > /tmp/uninstaller_cwd_after.txt\n"
"if [ -e cursor ]; then printf existing\\n > /tmp/shim_state.txt; else printf removed\\n > /tmp/shim_state.txt; fi\n"
),
),
(
"absolute_uninstall_path_matches_installed_cwd",
"/tmp/absolute_path_target",
(
"mnt='/tmp/absolute_path_target'\n"
"mount tmpfs \"$mnt\" -t tmpfs 2>/dev/null || true\n"
"cd \"$mnt\"\n"
"mkdir -p appdir\n"
"/bin/ln -h -f -s -- appdir/Cursor.app/Contents/Resources/app/bin/code cursor\n"
"printf '%s\\n' \"installed: $(pwd)/cursor\" > /tmp/created_by_installer.txt\n"
),
(
"printf '%s\\n' \"uninstaller cwd before: $(pwd)\" > /tmp/uninstaller_cwd_before.txt\n"
"sudo rm -rf '/tmp/absolute_path_target/cursor'\n"
"printf '%s\\n' \"uninstalled: $(pwd)\" > /tmp/uninstaller_cwd_after.txt\n"
"if [ -e cursor ]; then printf existing\\n > /tmp/shim_state.txt; else printf removed\\n > /tmp/shim_state.txt; fi\n"
),
),
]
script = "\n".join(f"case '{name}' in {name}) {setup}\\n{teardown}\\n;; esac" for name, cwd, setup, teardown in cases)
for case in cases:
name, cwd, setup, teardown = case
with tempfile.TemporaryDirectory() as tmpdir:
os.makedirs(cwd, exist_ok=True)
os.chdir(cwd)
subprocess.run(["sudo", "rm", "-rf", os.path.join(cwd, "appdir"), os.path.join(cwd, "cursor")],
check=False)
subprocess.run(["bash", "--", "-c", setup], check=True, text=True)
subprocess.run(["bash", "--", "-c", teardown], check=True, text=True)
print(f"--- {name}")
for p in ["created_by_installer.txt", "shim_state.txt", "uninstaller_cwd_before.txt", "uninstaller_cwd_after.txt"]:
try:
print(f"{p}: " + pathlib.Path(p).read_text().strip())
except FileNotFoundError as exc:
print(f"{p}: MISSING")
# clean between cases
subprocess.run(["sudo", "rm", "-rf", os.path.join(cwd, "appdir"), os.path.join(cwd, "cursor"), "/tmp/created_by_installer.txt", "/tmp/shim_state.txt"], check=False)
PYRepository: fleetdm/fleet
Length of output: 7703
🌐 Web query:
macOS /bin/ln -h symlink without creating directory documentation
💡 Result:
On macOS, the /bin/ln command does not automatically create parent directories when creating a symbolic link [1][2]. If the target path (the location where you want the link to exist) contains a directory that does not already exist, the command will fail with an error such as No such file or directory. You must ensure the destination directory exists before running the command [3][4]. To create a symbolic link, use the -s flag [1][5]: ln -s /path/to/original /path/to/link_name If you need to create the parent directory during the same operation, you can chain the commands using the && operator: mkdir -p /path/to/directory && ln -s /path/to/original /path/to/directory/link_name Key considerations for /bin/ln on macOS: - Existing Destination: If the target path (the link name) already exists, /bin/ln will generally fail unless you use the -f (force) option to remove the existing file or link first [1][6]. - Relative vs. Absolute Paths: When creating a symbolic link, the path to the original file is stored exactly as you type it [4]. If you use a relative path, it is interpreted relative to the location where the link is created, not relative to your current working directory [6][4]. - Directory Target: If the last argument provided to ln is an existing directory, the command will create a new link inside that directory with the same name as the target file [7][4]. If you want to force the link to be created as a specific file name even if a directory exists, you cannot easily override this behavior with standard /bin/ln flags on macOS [7][6].
Citations:
- 1: https://amazingalgorithms.com/commands/ln-macos/
- 2: https://macosbin.com/bin/ln
- 3: https://www.howtogeek.com/297721/how-to-create-and-use-symbolic-links-aka-symlinks-on-a-mac/
- 4: https://scriptingosx.com/2017/09/terminal-primer-part-6-symbolic-links/
- 5: https://osxdaily.com/2015/08/06/make-symbolic-links-command-line-mac-os-x/
- 6: https://manpages.debian.org/man/ln
- 7: https://www.gnu.org.cach3.com/software/coreutils/manual/html_node/ln-invocation.html
Create the Cursor shim at a fixed absolute path.
The installer unconditionally creates cursor in the installer’s working directory, but the uninstaller removes only "cursor" in the runner’s working directory. If the shell runs from anywhere else, the uninstall can leave the shim behind; if run from a different directory containing cursor, it can remove an unrelated path. Install and uninstall it from one stable absolute location instead.
🤖 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 installer’s final symlink creation and the uninstaller’s `sudo rm -rf
'cursor'` cleanup to use the same fixed absolute shim path, rather than the
current working directory. Ensure both `ln` creation and removal target that
stable location consistently, without affecting the application bundle handling.
| "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.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== target file =="
wc -l ee/maintained-apps/outputs/elgato-stream-deck/darwin.json || true
sed -n '1,80p' ee/maintained-apps/outputs/elgato-stream-deck/darwin.json || true
echo
echo "== remove_launchctl_service definition =="
python3 - <<'PY'
import json, re
from pathlib import Path
p=Path('ee/maintained-apps/outputs/elgato-stream-deck/darwin.json')
data=json.loads(p.read_text())
for k,v in data.items():
if isinstance(v,str) and 'remove_launchctl_service' in v:
lines=v.splitlines()
for i,l in enumerate(lines,1):
if 'remove_launchctl_service' in l:
start=max(1,i-15); end=min(len(lines),i+80)
print(f"--- output hash {k} lines {start}-{end} ---")
for n in range(start,end+1):
print(f"{n:4}: {lines[n-1]}")
print()
PY
echo
echo "== search for console_user and launchctl in file =="
python3 - <<'PY'
import json
data=json.load(open('ee/maintained-apps/outputs/elgato-stream-deck/darwin.json'))
samples=[(k,v) for k,v in zip(data.keys(), data.values())]
print("hashes:", list(data.keys())[:5])
script=list(data.values())[0]
for name in ['console_user','LOGGED_IN_USER','launchctl','/Library/LaunchAgents','/Library/LaunchDaemons']:
print(f"-- {name} occurrences --")
for n,line in enumerate(script.splitlines(),1):
if name in line:
print(f"{n}: {line}")
PY
echo
echo "== read-only behavioral probe of launchctl remove path for wildcard service patterns =="
python3 - <<'PY'
import sqlite3
import ast
import json
p='ee/maintained-apps/outputs/elgato-stream-deck/darwin.json'
s=json.load(open(p))[list(json.load(open(p)).keys())[0]]
ast_tree=ast.parse(s)
# locate function and calls in a text-aware way
script=s.splitlines()
def func_start(name):
for i,l in enumerate(script,1):
if l.strip()==f'{name}() {{':
return i
for name in ['remove_launchctl_service','forget_pkg','forget_receipt','remove_pkg_files','remove_receipt_files']:
print(f"{name}_start", func_start(name))
body=[]
in_func=False
for n,l in enumerate(script,1):
if 'remove_launchctl_service() {' in l:
in=True
if in_func:
body.append((n,l))
if in and n > 90: break
for n,l in body:
print(f"{n}: {l}")
PY
echo
echo "== shell docs from installed man page absent? =="
command -v launchctl && launchctl --version || trueRepository: fleetdm/fleet
Length of output: 13088
🌐 Web query:
macOS launchctl remove plist domain user job plist session launchd domain current user documentation
💡 Result:
To manage and remove jobs for the current user in modern macOS, the recommended approach is to use the bootout subcommand rather than the legacy load/unload syntax [1][2]. For the current user, the target domain is typically gui/, which represents the logged-in user's GUI session [2][3]. You can identify your user ID by running id -u [4][2]. To remove (stop and unload) a specific job for the current user: launchctl bootout gui/$(id -u)/[service-label] In this command, [service-label] refers to the unique label defined within the plist file (not the filename itself) [2]. Key considerations: 1. Modern vs. Legacy: While older documentation may reference load and unload, these are considered legacy [1][2]. The bootout command provides more robust feedback by reporting specific errors if a service fails to stop [5][2]. 2. Persistence: If you intend to permanently stop a service from starting on future logins, you should also disable it using the disable subcommand [1]: launchctl disable user/$(id -u)/[service-label] Disabling a service prevents it from being loaded again until it is explicitly re-enabled [1]. 3. Domain Targets: - gui/: Targets the user-login domain (GUI session) [6][2]. - user/: Targets the user domain, which may exist independently of a logged-in GUI session [5][7]. If you are trying to stop a service and find it persistently restarting, ensure you have used bootout to terminate the running instance and disable to modify the service's persistent state [1][2]. Removing the actual.plist file from ~/Library/LaunchAgents/ will also prevent the service from loading at the next login [2][8].
Citations:
- 1: https://johnturner.dev/notes/launchd-macos/
- 2: https://osxhub.com/macos-launchctl-manage-services/
- 3: https://apple.stackexchange.com/questions/126761/way-to-logout-a-user-from-the-command-line-in-os-x-10-9
- 4: https://stackoverflow.com/questions/49290174/osx-syntax-for-loading-a-single-launchagent-for-current-user
- 5: https://www.unix.com/man_page/mojave/1/launchctl/
- 6: https://manp.gs/mac/1/launchctl
- 7: https://ss64.com/mac/launchctl.html
- 8: https://lesspress.net/reference/launchd/
Remove Stream Deck launchd jobs from the logged-in user’s domain.
remove_launchctl_service() runs /bin/launchctl/sudo launchctl from the current process domain and uses $HOME for plist removal, not LOGGED_IN_USER. Running this as root can leave com.elgato.StreamDeck* jobs in the console user’s launchd domain after uninstall; target that user session explicitly when removing Stream Deck launchd services and plists.
🤖 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 and its Stream Deck call sites to target
LOGGED_IN_USER’s launchd session explicitly rather than the current/root process
domain. Use the console user’s home directory for non-system plist paths, and
invoke launchctl removal in that user’s domain while retaining sudo for
system-level services and plist cleanup.
| "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.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
quoted=$(bash -c 'printf "%s" '\''~/Library/Application Support/Mozilla'\''')
expanded=$(bash -c 'printf "%s" ~/Library/Application\ Support/Mozilla)
test "$quoted" = '~/Library/Application Support/Mozilla'
test "$expanded" != "$quoted"Repository: fleetdm/fleet
Length of output: 211
🏁 Script executed:
#!/bin/bash
set -eu
printf 'Quote-only tests:\n'
printf '%s\n' "$(bash -c "printf '%s' '~/Library/Application Support/Mozilla'")"
printf '%s\n' "$(bash -c "printf '%s' ~/Library/Application\ Support/Mozilla")"
printf '\nRelevant output file line:\n'
sed -n '1,35p' ee/maintained-apps/outputs/firefox@developer-edition/darwin.json
printf '\nBehavioral simulation of sudo rmdir invocation with single-quoted tilde:\n'
tmp="$(mktemp -d)"
bash -c "mkdir -p '${tmp//\'/\\'}/Users/$USER/Library/Application Support/Mozilla' && sudo rmdir '${tmp//\'/\\'}/Users/$USER/Library/Application Support/Mozilla' 2>&1 || true"Repository: fleetdm/fleet
Length of output: 7890
Fix the single-quoted rmdir paths.
Single-quoted ~ is not expanded by Bash, so these commands invoke rmdir with literal paths starting at the root ~ directory rather than the logged-in user’s home. Use the already resolved $LOGGED_IN_USER in double-quoted paths for these entries.
🤖 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 at line 19,
Update the four rmdir commands in the uninstall script to replace single-quoted
paths beginning with ~ with double-quoted paths rooted at
/Users/$LOGGED_IN_USER. Preserve the existing subpaths for Application
Support/Mozilla and the Mozilla cache directories while using the resolved
logged-in user home.
| "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.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate Kaleidoscope files =="
fd -i 'kaleidoscope|darwin\.json' ee/maintained-apps 2>/dev/null || true
echo "== Target file excerpt =="
cat -n ee/maintained-apps/outputs/kaleidoscope/darwin.json | sed -n '1,120p'
echo "== All kaleidoscope references in repo =="
rg -n --hidden -i 'kaleidoscope|app\.kaleidoscope\.v[67]|version_compare|bundle_identifier' ee/maintained-apps || true
echo "== git diff stat/name for context =="
git diff --stat || true
git diff --numstat ee/maintained-apps/outputs/kaleidoscope/darwin.json || trueRepository: fleetdm/fleet
Length of output: 50370
🌐 Web query:
Kaleidoscope v7 macOS bundle identifier app.kaleidoscope.v7 app.kaleidoscope.v6
💡 Result:
The Kaleidoscope application for macOS uses the bundle identifier app.kaleidoscope.v7 for version 7 [1]. Previous major versions followed a consistent pattern, with version 6 using the identifier app.kaleidoscope.v6 [1]. These bundle identifiers are explicitly referenced in the official Homebrew Cask configuration for the application, which defines the uninstall and cleanup paths using the app.kaleidoscope.v* pattern [1]. If you need to verify the bundle identifier for a specific installation of Kaleidoscope on your machine, you can use the terminal command: osascript -e 'id of app "Kaleidoscope"' [2] Alternatively, you can inspect the Info.plist file located within the application package (Contents/Info.plist) and look for the CFBundleIdentifier key [3][4].
Citations:
- 1: https://github.com/Homebrew/homebrew-cask/blob/7ab5ddf8fd0fc54e2361f87ae0c288a17481510d/Casks/k/kaleidoscope.rb
- 2: https://macbundleid.lemonproductions.ca/
- 3: https://support.apple.com/guide/deployment/get-the-bundle-id-for-a-mac-app-dep0af2cd611/web
- 4: https://support.jamf.com/en/articles/11034093-how-to-find-the-bundle-id-of-an-app-on-macos-or-ios
🌐 Web query:
site:github.com Kaleidoscope app.kaleidoscope.v7 macOS bundle identifier
💡 Result:
The macOS bundle identifier for modern versions of the Kaleidoscope application is app.kaleidoscope.v6 (for version 6.x) [1][2][3], while older versions use app.kaleidoscope.v3 [4] and com.blackpixel.kaleidoscope [1][5][4]. The identifier follows the pattern app.kaleidoscope.v{major_version}, where {major_version} corresponds to the major release of the application [1][4]. This structure is explicitly used in the application's configuration files, uninstall scripts, and file path locations (such as application support and caches) to distinguish between different major versions of the software on a single system [1][2][4].
Citations:
- 1: https://github.com/Homebrew/homebrew-cask/blob/0067a88c0f3d765ec1e8ea70d1968472378eb376/Casks/k/kaleidoscope.rb
- 2: https://github.com/Homebrew/homebrew-cask/blob/7ab5ddf8fd0fc54e2361f87ae0c288a17481510d/Casks/k/kaleidoscope.rb
- 3: https://github.com/Homebrew/homebrew-cask/blob/45658406e9109543c11041e3dc0b696c2e804101/Casks/k/kaleidoscope.rb
- 4: https://github.com/Homebrew/homebrew-cask/blob/0067a88c0f3d765ec1e8ea70d1968472378eb376/Casks/k/kaleidoscope@3.rb
- 5: https://github.com/Homebrew/homebrew-cask/blob/417b156d4adc10fa3c16b6d66ec339831604102c/Casks/k/kaleidoscope@2.rb
Use the Kaleidoscope v7 bundle identifier consistently.
The installer and detection now target app.kaleidoscope.v7/7.0, but the install script still quits/relaunches app.kaleidoscope.v6. Update the v6 references in lines 19-20 or keep the app at v6 everywhere if this payload is not intended for v7.
🤖 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 v6 bundle identifier references in the installer and
detection flow to use app.kaleidoscope.v7 consistently with the version 7.0
payload, including the quit/relaunch commands. If this payload is intentionally
for v6, instead align all version and bundle-identifier references to v6.
| "refs": { | ||
| "3ec00885": "#!/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.nextcloud.desktopclient'\nquit_application 'com.nextcloud.desktopclient'\nremove_pkg_files 'com.nextcloud.desktopclient'\nforget_pkg 'com.nextcloud.desktopclient'\nsudo rm -rf '/Applications/Nextcloud.app'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.nextcloud.desktopclient.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Nextcloud'\ntrash $LOGGED_IN_USER '~/Library/Caches/Nextcloud'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.nextcloud.desktopclient.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/com.nextcloud.desktopclient'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.nextcloud.desktopclient.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/Nextcloud'\n", | ||
| "c18d4d3b": "#!/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.nextcloud.desktopclient'\nsudo installer -pkg \"$TMPDIR/Nextcloud-33.0.7.pkg\" -target /\nrelaunch_application 'com.nextcloud.desktopclient'\n" | ||
| "d9838806": "#!/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.nextcloud.desktopclient'\nsudo installer -pkg \"$TMPDIR/Nextcloud-34.0.0.pkg\" -target /\nrelaunch_application 'com.nextcloud.desktopclient'\n" |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Propagate critical installer failures before relaunching.
Each changed installer payload can return success after a failed install or copy because the critical command status is ignored and relaunch_application ends successfully.
ee/maintained-apps/outputs/nextcloud/darwin.json#L20-L20: capture and validatesudo installer -pkg ...before relaunching.ee/maintained-apps/outputs/chatgpt-atlas/darwin.json#L20-L20: validate the DMG extraction and application copy commands before relaunching.ee/maintained-apps/outputs/opencode-desktop/darwin.json#L19-L19: validate the DMG extraction and application copy commands before relaunching.
📍 Affects 3 files
ee/maintained-apps/outputs/nextcloud/darwin.json#L20-L20(this comment)ee/maintained-apps/outputs/chatgpt-atlas/darwin.json#L20-L20ee/maintained-apps/outputs/opencode-desktop/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/nextcloud/darwin.json` at line 20, Propagate
critical installer failures before relaunching: in
ee/maintained-apps/outputs/nextcloud/darwin.json at line 20, capture and
validate the sudo installer command status before calling relaunch_application;
in ee/maintained-apps/outputs/chatgpt-atlas/darwin.json at line 20 and
ee/maintained-apps/outputs/opencode-desktop/darwin.json at line 19, validate DMG
extraction and application copy command statuses before relaunching, ensuring
failures are reported and returned rather than allowing the payload to succeed.
| "refs": { | ||
| "727dc41e": "#!/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 'ai.opencode.desktop'\nif [ -d \"$APPDIR/OpenCode.app\" ]; then\n\tsudo mv \"$APPDIR/OpenCode.app\" \"$TMPDIR/OpenCode.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/OpenCode.app\" \"$APPDIR\"\nrelaunch_application 'ai.opencode.desktop'\n", | ||
| "ad62b190": "#!/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/OpenCode.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/Logs/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ai.opencode.desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/ai.opencode.desktop.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/ai.opencode.desktop'\n" | ||
| "99fcb3f1": "#!/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/OpenCode.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/ai.opencode.desktop.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Caches/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/Logs/ai.opencode.desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ai.opencode.desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/ai.opencode.desktop.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/ai.opencode.desktop'\n" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Restore the recent-documents cleanup target.
The new uninstaller no longer removes ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/ai.opencode.desktop.sfl*, leaving stale OpenCode entries after uninstall.
🤖 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/opencode-desktop/darwin.json` at line 20, Restore
the recent-documents cleanup call in the uninstaller by adding the
ai.opencode.desktop.sfl* target to the sequence of trash calls after the main
application-support cleanup. Preserve the existing trash function’s glob
handling so all matching recent-document files are removed.
| "version": "10.1.1", | ||
| "queries": { | ||
| "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.rightfontapp.RightFont5';", | ||
| "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.rightfontapp.RightFont5' AND version_compare(bundle_short_version, '10.1') < 0);" | ||
| "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.rightfontapp.RightFont5' AND version_compare(bundle_short_version, '10.1.1') < 0);" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== matching maintained-app manifests =="
fd 'darwin\.json$' ee/maintained-apps/outputs | sed -n '1,120p'
echo
echo "== rightfont manifest =="
cat -n ee/maintained-apps/outputs/rightfont/darwin.json
echo
echo "== roboform manifest =="
cat -n ee/maintained-apps/outputs/roboform/darwin.json
echo
echo "== generic download URL/checksum usage in maintained-app outputs =="
python3 - <<'PY'
import json, pathlib
root = pathlib.Path('ee/maintained-apps/outputs')
for p in sorted(root.rglob('darwin.json')):
try:
data=json.loads(p.read_text())
except Exception as e:
print(f"{p}: parse error: {e}")
continue
url=data.get('url') or data.get('download_url')
checksum=data.get('sha256') or data.get('checksum')
print(f"{p}: url={url}, sha256/checksum={checksum}")
PYRepository: fleetdm/fleet
Length of output: 50370
Pin the installer artifacts and provide checksums. These manifests report updated versions but still download through mutable vendor endpoints and keep sha256: no_check, so Fleet can’t ensure the built app matches the advertised version.
ee/maintained-apps/outputs/rightfont/darwin.json: add an immutable10.1.1artifact URL and checksum, or verify the downloaded build before publishing.ee/maintained-apps/outputs/roboform/darwin.json: add an immutable9.9.5artifact URL and checksum, or verify the downloaded build before publishing.
📍 Affects 2 files
ee/maintained-apps/outputs/rightfont/darwin.json#L4-L7(this comment)ee/maintained-apps/outputs/roboform/darwin.json#L4-L7
🤖 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/rightfont/darwin.json` around lines 4 - 7, Pin the
installer artifacts and replace sha256: no_check with verified checksums so
Fleet can validate the advertised versions. Update
ee/maintained-apps/outputs/rightfont/darwin.json for immutable version 10.1.1
artifacts and ee/maintained-apps/outputs/roboform/darwin.json for immutable
version 9.9.5 artifacts, or implement equivalent pre-publication build
verification in each manifest’s artifact configuration.
| ], | ||
| "refs": { | ||
| "6335aa0a": "$softwareName = \"Spyder\"\n$softwareNameLike = \"*$softwareName*\"\n# Registry publisher from the winget manifest's AppsAndFeaturesEntries, which\n# differs from the package Publisher (\"Spyder Project Contributors and others\").\n$publisher = \"Spyder-IDE\"\n$uninstallArgs = \"/S\"\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$exitCode = 0\n\ntry {\n [array]$uninstallKeys = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath }\n\n $foundUninstaller = $false\n foreach ($key in $uninstallKeys) {\n if ($key.DisplayName -like $softwareNameLike -and $key.Publisher -eq $publisher) {\n $foundUninstaller = $true\n $uninstallCommand = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }\n if ($uninstallCommand -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n } elseif ($uninstallCommand -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n }\n Write-Host \"Uninstall command: $uninstallCommand\"; Write-Host \"Uninstall args: $uninstallArgs\"\n $processOptions = @{ FilePath = $uninstallCommand; PassThru = $true; Wait = $true }\n if ($uninstallArgs -ne '') { $processOptions.ArgumentList = $uninstallArgs }\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode; Write-Host \"Uninstall exit code: $exitCode\"; break\n }\n }\n if (-not $foundUninstaller) { Write-Host \"Uninstaller for '$softwareName' not found.\"; Exit 1 }\n} catch { Write-Host \"Error: $_\"; Exit 1 }\n\nExit $exitCode\n", | ||
| "1fb72c38": "$softwareName = \"Spyder\"\n$softwareNameLike = \"*$softwareName*\"\n# Registry publisher from the winget manifest's AppsAndFeaturesEntries, which\n# differs from the package Publisher (\"Spyder Project Contributors and others\").\n$publisher = \"Spyder-IDE\"\n$uninstallArgs = \"/S\"\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$exitCode = 0\n\ntry {\n [array]$uninstallKeys = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath }\n\n $foundUninstaller = $false\n foreach ($key in $uninstallKeys) {\n if ($key.DisplayName -like $softwareNameLike -and $key.Publisher -eq $publisher) {\n $foundUninstaller = $true\n $uninstallCommand = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }\n if ($uninstallCommand -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n } elseif ($uninstallCommand -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n }\n Write-Host \"Uninstall command: $uninstallCommand\"; Write-Host \"Uninstall args: $uninstallArgs\"\n $processOptions = @{ FilePath = $uninstallCommand; PassThru = $true; Wait = $true }\n if ($uninstallArgs -ne '') { $processOptions.ArgumentList = $uninstallArgs }\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode; Write-Host \"Uninstall exit code: $exitCode\"; break\n }\n }\n if (-not $foundUninstaller) { Write-Host \"Uninstaller for '$softwareName' not found.\"; Exit 0 }\n} catch { Write-Host \"Error: $_\"; Exit 1 }\n\nExit $exitCode\n", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Do not report success when the uninstaller is merely missing.
The new Exit 0 path treats every “no matching registry entry” case as successful. Because registry lookup errors are suppressed and there is no independent absence check, Spyder can remain installed while Fleet records the uninstall as complete. Return success only after confirming the app is absent; otherwise propagate the lookup or uninstall failure.
🤖 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/spyder/windows.json` at line 19, Update the
uninstall flow around $uninstallKeys, $foundUninstaller, and the “not found”
branch so a missing matching registry entry is not reported as successful
without independently confirming Spyder is absent. Preserve successful exit only
when the app is verified absent or the uninstaller completes successfully;
otherwise stop suppressing or propagate registry lookup errors and return a
failure status.
Script Diff Resultsee/maintained-apps/outputs/1password/darwin.json=== Install Script (no changes) ===
=== Uninstall // c927cf5a -> a642a51c ===
--- /tmp/old.Qog9br 2026-07-29 03:53:38.051599394 +0000
+++ /tmp/new.bBR5pL 2026-07-29 03:53:38.051599394 +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.QB32Pr 2026-07-29 03:53:38.105599998 +0000
+++ /tmp/new.2xSFJb 2026-07-29 03:53:38.105599998 +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/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.vCmSem 2026-07-29 03:53:38.217601253 +0000
+++ /tmp/new.DLFo0l 2026-07-29 03:53:38.218601264 +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.sG6avu 2026-07-29 03:53:38.381603090 +0000
+++ /tmp/new.EKcXor 2026-07-29 03:53:38.381603090 +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.cX1OBR 2026-07-29 03:53:38.512604558 +0000
+++ /tmp/new.7Q4ezU 2026-07-29 03:53:38.512604558 +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.kRw92P 2026-07-29 03:53:38.653606137 +0000
+++ /tmp/new.thAntp 2026-07-29 03:53:38.653606137 +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.UoQkyT 2026-07-29 03:53:38.866608523 +0000
+++ /tmp/new.Q7I12b 2026-07-29 03:53:38.866608523 +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.oXwHMB 2026-07-29 03:53:38.989609901 +0000
+++ /tmp/new.cZeQnW 2026-07-29 03:53:38.989609901 +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.OIdNuK 2026-07-29 03:53:39.011610147 +0000
+++ /tmp/new.Ibwo8w 2026-07-29 03:53:39.011610147 +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.kyHziV 2026-07-29 03:53:39.171611444 +0000
+++ /tmp/new.HaV0fw 2026-07-29 03:53:39.171611444 +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.z6MejX 2026-07-29 03:53:39.318612492 +0000
+++ /tmp/new.q5dwdM 2026-07-29 03:53:39.319612499 +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.D1VuFw 2026-07-29 03:53:39.489613711 +0000
+++ /tmp/new.9gd8xb 2026-07-29 03:53:39.490613718 +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.3TN5kV 2026-07-29 03:53:39.612614588 +0000
+++ /tmp/new.7EbSho 2026-07-29 03:53:39.612614588 +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.RI2U8z 2026-07-29 03:53:39.659614923 +0000
+++ /tmp/new.hpDUV5 2026-07-29 03:53:39.659614923 +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.XeC8CS 2026-07-29 03:53:39.767615693 +0000
+++ /tmp/new.2XtIJE 2026-07-29 03:53:39.767615693 +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.UVR5WM 2026-07-29 03:53:39.872616442 +0000
+++ /tmp/new.p2eNpe 2026-07-29 03:53:39.872616442 +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.rdmfa7 2026-07-29 03:53:40.030617568 +0000
+++ /tmp/new.JyqYx0 2026-07-29 03:53:40.031617575 +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.ajp02P 2026-07-29 03:53:40.180618638 +0000
+++ /tmp/new.i1ApmS 2026-07-29 03:53:40.181618645 +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.xXqvJZ 2026-07-29 03:53:40.243619087 +0000
+++ /tmp/new.3cXAsn 2026-07-29 03:53:40.243619087 +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.rcG5nH 2026-07-29 03:53:40.297619472 +0000
+++ /tmp/new.Ellaqs 2026-07-29 03:53:40.297619472 +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.RCKPC4 2026-07-29 03:53:40.348619836 +0000
+++ /tmp/new.uCpOJ4 2026-07-29 03:53:40.348619836 +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.PC09bJ 2026-07-29 03:53:40.400620207 +0000
+++ /tmp/new.umX4dc 2026-07-29 03:53:40.400620207 +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.W883fI 2026-07-29 03:53:40.452620577 +0000
+++ /tmp/new.gZPzu7 2026-07-29 03:53:40.452620577 +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.RfEqH2 2026-07-29 03:53:40.549621269 +0000
+++ /tmp/new.rl9SLk 2026-07-29 03:53:40.549621269 +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.9I3jSi 2026-07-29 03:53:40.643621939 +0000
+++ /tmp/new.KCUeWM 2026-07-29 03:53:40.643621939 +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.txMa6d 2026-07-29 03:53:40.835623308 +0000
+++ /tmp/new.2GjDWn 2026-07-29 03:53:40.835623308 +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.Cojn2v 2026-07-29 03:53:41.101625205 +0000
+++ /tmp/new.fC2xct 2026-07-29 03:53:41.101625205 +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.UWEBc3 2026-07-29 03:53:41.145625518 +0000
+++ /tmp/new.9MTkI0 2026-07-29 03:53:41.146625525 +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.Hh0d1Z 2026-07-29 03:53:41.231626131 +0000
+++ /tmp/new.rQocnt 2026-07-29 03:53:41.232626139 +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.q9osLm 2026-07-29 03:53:41.609628827 +0000
+++ /tmp/new.3hhIwZ 2026-07-29 03:53:41.609628827 +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) === |
Automated ingestion of latest Fleet-maintained app data.
Summary by CodeRabbit