Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.3.1] - 2025-10-06
### Changed
- Refactored the uninstall script with better error handling and logging.

## [2.3.0] - 2025-09-18
### Changed
- Updated UI elements to match the new look introduced in macOS 26 (Tahoe).
Expand Down
78 changes: 39 additions & 39 deletions SupportCompanion/Info.plist
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>CFBundleShortVersionString</key>
<string>2.3.0</string>
<key>CFBundleVersion</key>
<string>2.3.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.github.macadmins.SupportCompanion</string>
<key>CFBundleURLSchemes</key>
<array>
<string>supportcompanion</string>
</array>
</dict>
</array>
<key>SMPrivilegedExecutables</key>
<dict>
<key>com.github.macadmins.SupportCompanion.helper</key>
<string>anchor apple generic and identifier &quot;com.github.macadmins.SupportCompanion.helper&quot; and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = $(TEAM_ID))</string>
</dict>
</dict>
</plist>
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>CFBundleShortVersionString</key>
<string>2.3.1</string>
<key>CFBundleVersion</key>
<string>2.3.1</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.github.macadmins.SupportCompanion</string>
<key>CFBundleURLSchemes</key>
<array>
<string>supportcompanion</string>
</array>
</dict>
</array>
<key>SMPrivilegedExecutables</key>
<dict>
<key>com.github.macadmins.SupportCompanion.helper</key>
<string>anchor apple generic and identifier "com.github.macadmins.SupportCompanion.helper" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = $(TEAM_ID))</string>
</dict>
</dict>
</plist>
155 changes: 119 additions & 36 deletions SupportCompanion/Scripts/Uninstall.zsh
Original file line number Diff line number Diff line change
@@ -1,40 +1,123 @@
#!/bin/zsh

# Script requires root so check for root access
if [ $(id -u) -ne 0 ]; then
echo "Please run this script as root or using sudo"
exit 1
set -u # error on unset vars

# --- helpers ---------------------------------------------------------------
log() { print -- "[uninstall] $*" }
warn() { print -- "[warn] $*" >&2 }
err() { print -- "[error] $*" >&2 }

# run a command, ignore if it fails; print message
_try() {
local desc="$1"; shift
if "$@"; then
log "$desc: ok"
else
warn "$desc: skipped/failed"
fi
}

# delete a file/dir if it exists
_rm_if_exists() {
local path="$1"
if [ -e "$path" ] || [ -L "$path" ]; then
/bin/rm -rf -- "$path" && log "removed: $path" || warn "failed to remove: $path"
else
log "not present: $path"
fi
}

# get console user + uid
get_console_user() {
/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" \
| /usr/bin/awk '/Name :/ && $3 != "loginwindow" { print $3 }'
}
get_console_uid() {
/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" \
| /usr/bin/awk '/kCGSSessionUserIDKey/ {print $NF; exit}'
}

# --- preflight -------------------------------------------------------------
if [ "$(id -u)" -ne 0 ]; then
err "Please run this script as root or using sudo"
exit 1
fi
# Use Apple Recommended Method to detect the user signed in to the desktop
current_user=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }')
console_user_uid=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/kCGSSessionUserIDKey/ {print $NF; exit}' )
# Kill the process
echo "Killing the process..."
pkill -f SupportCompanion
# Remove user defaults
echo "Removing user defaults..."
sudo -u "${current_user}" defaults delete com.github.macadmins.SupportCompanion
# Unload launchctl job
echo "Unloading helepr launchctl job..."
launchctl unload -w /Library/LaunchDaemons/com.github.macadmins.SupportCompanion.helper.plist
# Remove launchctl job
echo "Removing helper launchctl job..."
rm -f /Library/LaunchDaemons/com.github.macadmins.SupportCompanion.helper.plist
# Remove launch agent
if [ -f "/Library/LaunchAgents/com.github.macadmins.SupportCompanion.agent.plist" ]; then
echo "Unloading launch agent..."
/bin/launchctl asuser "${console_user_uid}" /bin/launchctl unload -w /Library/LaunchAgents/com.github.macadmins.SupportCompanion.agent.plist
echo "Removing launch agent..."
rm /Library/LaunchAgents/com.github.macadmins.SupportCompanion.agent.plist

APP_ID="com.github.macadmins.SupportCompanion"
HELPER_ID="com.github.macadmins.SupportCompanion.helper"
AGENT_ID="com.github.macadmins.SupportCompanion.agent"

APP_PATH="/Applications/SupportCompanion.app"
HELPER_PATH="/Library/PrivilegedHelperTools/${HELPER_ID}"
DAEMON_PLIST="/Library/LaunchDaemons/${HELPER_ID}.plist"
AGENT_PLIST="/Library/LaunchAgents/${AGENT_ID}.plist"

CONSOLE_USER=$(get_console_user || true)
CONSOLE_UID=$(get_console_uid || true)

log "Console user: ${CONSOLE_USER:-unknown} (uid ${CONSOLE_UID:-n/a})"

# --- stop processes --------------------------------------------------------
log "Stopping application and helper if running"
_try "kill app" pkill -f SupportCompanion

# --- defaults cleanup (non-fatal) -----------------------------------------
if [ -n "${CONSOLE_USER:-}" ]; then
# Only attempt if domain exists to avoid noisy errors
if sudo -u "$CONSOLE_USER" /usr/bin/defaults domains | /usr/bin/grep -q -- "$APP_ID"; then
_try "delete user defaults" sudo -u "$CONSOLE_USER" /usr/bin/defaults delete "$APP_ID"
else
log "user defaults domain not present: $APP_ID"
fi
else
warn "No console user detected; skipping user defaults removal"
fi
# Remove the app
echo "Removing the app..."
rm -rf /Applications/SupportCompanion.app
# Remove app data
echo "Removing helper..."
rm -rf "/Library/PrivilegedHelperTools/com.github.macadmins.SupportCompanion.helper"
# Forget the package
echo "Forgetting the package..."
pkgutil --forget com.github.macadmins.SupportCompanion > /dev/null 2>&1
pkgutil --forget com.github.macadmins.SupportCompanion.LaunchAgent > /dev/null 2>&1
pkgutil --forget com.github.macadmins.SupportCompanion.suite > /dev/null 2>&1

# --- launchd: daemon (helper) ---------------------------------------------
if [ -f "$DAEMON_PLIST" ]; then
log "Unloading helper launch daemon"
_try "launchctl unload daemon" /bin/launchctl unload -w "$DAEMON_PLIST"
else
log "daemon plist not present: $DAEMON_PLIST"
fi

# Remove daemon plist regardless of unload outcome
_rm_if_exists "$DAEMON_PLIST"

# --- launchd: agent (per-user) --------------------------------------------
if [ -f "$AGENT_PLIST" ]; then
if [ -n "${CONSOLE_UID:-}" ]; then
log "Unloading launch agent for uid $CONSOLE_UID"
_try "launchctl unload agent" /bin/launchctl asuser "$CONSOLE_UID" /bin/launchctl unload -w "$AGENT_PLIST"
else
warn "No console uid; unloading agent in current context"
_try "launchctl unload agent (fallback)" /bin/launchctl unload -w "$AGENT_PLIST"
fi
else
log "agent plist not present: $AGENT_PLIST"
fi

# Remove agent plist
_rm_if_exists "$AGENT_PLIST"

# --- remove bits -----------------------------------------------------------
log "Removing installed components"
_rm_if_exists "$APP_PATH"
_rm_if_exists "$HELPER_PATH"

# --- pkg receipts -------------------------------------------
forget_if_present() {
local package="$1"
if /usr/sbin/pkgutil --pkgs | /usr/bin/grep -qx -- "$package"; then
_try "forget $package" /usr/sbin/pkgutil --forget "$package"
else
log "receipt not present: $package"
fi
}

forget_if_present "${APP_ID}"
forget_if_present "${APP_ID}.LaunchAgent"
forget_if_present "${APP_ID}.suite"

log "Uninstall completed"
exit 0