diff --git a/repertory/Install repertory.command b/repertory/Install repertory.command index 8b06249b..7a0d0b81 100644 --- a/repertory/Install repertory.command +++ b/repertory/Install repertory.command @@ -134,6 +134,19 @@ unmount_existing_repertory_volumes() { # ----- user LaunchAgents (by LABEL_PREFIX only) ----- get_plist_label() { /usr/bin/defaults read "$1" Label 2>/dev/null || /usr/libexec/PlistBuddy -c "Print :Label" "$1" 2>/dev/null || basename "$1" .plist; } +# Return the executable path a LaunchAgent runs (ProgramArguments[0] or Program). +# Echoes empty string if neither is present. +get_plist_exec_path() { + local plist="$1" arg0="" + # Prefer ProgramArguments[0] + arg0="$(/usr/libexec/PlistBuddy -c 'Print :ProgramArguments:0' "$plist" 2>/dev/null || true)" + if [[ -z "$arg0" ]]; then + # Fallback to Program (older style) + arg0="$(/usr/libexec/PlistBuddy -c 'Print :Program' "$plist" 2>/dev/null || true)" + fi + printf '%s\n' "$arg0" +} + snapshot_launchagents_user() { local user_agents="$HOME/Library/LaunchAgents" snapfile="$(/usr/bin/mktemp "/tmp/repertory_launchagents.XXXXXX")" || snapfile="" @@ -141,16 +154,48 @@ snapshot_launchagents_user() { warn "Could not create temporary snapshot file; skipping LaunchAgent restart snapshot." return 0 fi - if [[ -d "$user_agents" ]]; then - /usr/bin/find "$user_agents" -maxdepth 1 -type f -name "${LABEL_PREFIX}"'*.plist' -print 2>/dev/null | - while IFS= read -r plist; do - [[ -z "$plist" ]] && continue - local label - label="$(get_plist_label "$plist")" - [[ -n "$label" && "$label" == "${LABEL_PREFIX}"* ]] || continue - printf "%s\t%s\n" "$plist" "$label" >>"$snapfile" - done - fi + [[ -d "$user_agents" ]] || return 0 + + # We collect non-UI first, then UI last, to preserve restart order later. + local tmp_nonui tmp_ui + tmp_nonui="$(/usr/bin/mktemp "/tmp/repertory_launchagents.nonui.XXXXXX")" || tmp_nonui="" + tmp_ui="$(/usr/bin/mktemp "/tmp/repertory_launchagents.ui.XXXXXX")" || tmp_ui="" + + /usr/bin/find "$user_agents" -maxdepth 1 -type f -name "${LABEL_PREFIX}"'*.plist' -print 2>/dev/null | + while IFS= read -r plist; do + [[ -z "$plist" ]] && continue + + # Label must match the prefix + local label + label="$(get_plist_label "$plist")" + [[ -n "$label" && "$label" == "${LABEL_PREFIX}"* ]] || continue + + # Executable must point into the *installed* app path + local exec_path + exec_path="$(get_plist_exec_path "$plist")" + [[ -n "$exec_path" ]] || continue + # Normalize: only accept absolute paths under $dest_app (e.g. .../repertory.app/Contents/...) + if [[ "$exec_path" != "$dest_app/"* ]]; then + # Not one of ours; skip + continue + fi + + # Defer UI label to the end + if [[ "$label" == "$UI_LABEL" ]]; then + [[ -n "$tmp_ui" ]] && printf "%s\t%s\n" "$plist" "$label" >>"$tmp_ui" + else + [[ -n "$tmp_nonui" ]] && printf "%s\t%s\n" "$plist" "$label" >>"$tmp_nonui" + fi + done + + # Stitch together: non-UI first, then UI + [[ -s "$tmp_nonui" ]] && /bin/cat "$tmp_nonui" >>"$snapfile" + [[ -s "$tmp_ui" ]] && /bin/cat "$tmp_ui" >>"$snapfile" + + [[ -n "$tmp_nonui" ]] && /bin/rm -f "$tmp_nonui" 2>/dev/null || true + [[ -n "$tmp_ui" ]] && /bin/rm -f "$tmp_ui" 2>/dev/null || true + + log "Snapshot contains $(/usr/bin/wc -l <"$snapfile" 2>/dev/null || echo 0) LaunchAgent(s)." } unload_launchd_helpers_user() {