Add Pd (Pure Data) as a macOS FMA - #47056
Conversation
Add support for Pd (Pure Data) on macOS: new Homebrew input manifest and installer script, outputs and apps entry, frontend icon and image, and a version transformer. - Add ee/maintained-apps/inputs/homebrew/pd.json and install script scripts/pd-install.sh that unzip the Homebrew archive, mount the embedded DMG, copy the .app, and handle quitting/relaunching the app. - Add ee/maintained-apps/outputs/pd/darwin.json with version, installer, hashes, and embedded install/uninstall script refs; add app entry to ee/maintained-apps/outputs/apps.json. - Register Pd in Homebrew external refs mapping and add PdVersionTransformer to convert Homebrew version strings like "0.56-3" to the dotted macOS bundle_short_version form "0.56.3" so version_compare and patch detection work correctly. - Add frontend icon component and PNG asset, and update the icon index to include Pd.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #47056 +/- ##
=======================================
Coverage 67.03% 67.03%
=======================================
Files 2886 2887 +1
Lines 225155 225162 +7
Branches 11637 11637
=======================================
+ Hits 150938 150946 +8
- Misses 60544 60545 +1
+ Partials 13673 13671 -2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
There was a problem hiding this comment.
Pull request overview
This PR adds Pd (Pure Data) as a Fleet-maintained app (FMA) for macOS by introducing a Homebrew input manifest and install script, generating the corresponding output manifest and apps catalog entry, wiring a Homebrew version transformer to normalize Pd’s version format for patch/version comparisons, and adding a frontend software icon mapping.
Changes:
- Add Pd Homebrew input manifest + macOS install script (zip → dmg → app copy flow).
- Generate Pd macOS output manifest (version/queries/installer + embedded install/uninstall refs) and register Pd in the FMA app catalog.
- Add a Pd Homebrew version transformer and frontend icon component/mapping.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/pages/SoftwarePage/components/icons/Pd.tsx | Adds Pd icon component for software UI. |
| frontend/pages/SoftwarePage/components/icons/index.ts | Registers Pd icon and maps software name key to the new icon. |
| ee/maintained-apps/outputs/pd/darwin.json | Adds generated Pd macOS output manifest including embedded scripts. |
| ee/maintained-apps/outputs/apps.json | Adds Pd entry to the FMA apps catalog. |
| ee/maintained-apps/inputs/homebrew/scripts/pd-install.sh | Adds Pd install script to extract zip, mount DMG, install .app, and relaunch if needed. |
| ee/maintained-apps/inputs/homebrew/pd.json | Adds Pd Homebrew input manifest (token/slug/identifier/categories/script path). |
| ee/maintained-apps/ingesters/homebrew/external_refs/version_shortener.go | Adds PdVersionTransformer to normalize Homebrew version strings for macOS comparisons. |
| ee/maintained-apps/ingesters/homebrew/external_refs/main.go | Registers PdVersionTransformer in the external refs mapping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # variables | ||
| APPDIR="/Applications/" | ||
| TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")") | ||
| # functions |
| // PdVersionTransformer converts Homebrew's Pd version scheme (e.g. "0.56-3") to | ||
| // the dotted form macOS reports as bundle_short_version (e.g. "0.56.3"). | ||
| // Without this, osquery's version_compare treats "0.56-3" and "0.56.3" as | ||
| // different versions and patch policy detection breaks. | ||
| func PdVersionTransformer(app *maintained_apps.FMAManifestApp) (*maintained_apps.FMAManifestApp, error) { | ||
| if app.Version == "" { | ||
| return app, errors.New("empty version for Pd") | ||
| } | ||
| app.Version = strings.ReplaceAll(app.Version, "-", ".") | ||
| return app, nil |
| ], | ||
| "refs": { | ||
| "2eac86b0": "#!/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/Pd-0.56-3.app\"\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.puredata.pd.pd-gui.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.puredata.pd.pd-gui.savedState'\n", | ||
| "8a005b0c": "#!/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\n# Pd's download is a .zip that contains a .dmg, which in turn contains the .app.\n# The app folder name carries the version (e.g. \"Pd-0.56-3.app\"), so unzip\n# first, then mount the embedded DMG and copy whichever .app it contains. This\n# keeps the script version-agnostic across Homebrew bumps.\nEXTRACT_DIR=$(mktemp -d /tmp/pd_extract_XXXXXX)\nunzip -q \"$INSTALLER_PATH\" -d \"$EXTRACT_DIR\"\nDMG_PATH=$(find \"$EXTRACT_DIR\" -maxdepth 2 -name \"*.dmg\" | head -1)\nif [ -z \"$DMG_PATH\" ]; then\n echo \"No DMG found inside the Pd archive\" >&2\n exit 1\nfi\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$DMG_PATH\" || exit 1\nAPP_BUNDLE=$(find \"$MOUNT_POINT\" -maxdepth 1 -name \"*.app\" | head -1)\nif [ -z \"$APP_BUNDLE\" ]; then\n echo \"No .app found inside the Pd DMG\" >&2\n hdiutil detach \"$MOUNT_POINT\" || true\n exit 1\nfi\nAPP_NAME=$(basename \"$APP_BUNDLE\")\n# copy to the applications folder\nquit_and_track_application 'org.puredata.pd.pd-gui'\nif [ -d \"$APPDIR/$APP_NAME\" ]; then\n\tsudo mv \"$APPDIR/$APP_NAME\" \"$TMPDIR/$APP_NAME.bkp\"\nfi\nsudo cp -R \"$APP_BUNDLE\" \"$APPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\nrelaunch_application 'org.puredata.pd.pd-gui'\n" |
WalkthroughThis PR adds comprehensive support for Pure Data (Pd) as a managed macOS application. It introduces a version transformer that normalizes Homebrew's dash-delimited Pd versions to dot-delimited format, implements installation and uninstallation scripts with app lifecycle management (quit before replacement, relaunch in correct GUI session), defines Homebrew input metadata and a complete macOS maintenance manifest with version checks and embedded scripts, and adds a frontend icon component registered for UI display. Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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: 2
🤖 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/inputs/homebrew/scripts/pd-install.sh`:
- Around line 117-123: The script only handles the exact APP_NAME, leaving older
versioned bundles (e.g., Pd-1.0.app, Pd-1.1.app) behind; before copying, derive
a stable prefix from APP_NAME (e.g., PREFIX="${APP_NAME%%-*}" or strip version
suffix) and locate all existing bundles in APPDIR that start with that prefix
(use APPDIR/"${PREFIX}"*.app), then quit via quit_and_track_application and move
or remove those matches to TMPDIR as backups (instead of only moving
"$APPDIR/$APP_NAME"), ensuring all prior Pd installs are cleaned up before sudo
cp -R "$APP_BUNDLE" "$APPDIR".
In `@ee/maintained-apps/outputs/pd/darwin.json`:
- Around line 19-20: The uninstall step currently runs sudo rm -rf
"$APPDIR/Pd-0.56-3.app" which only removes one hard-coded version; replace that
with logic that removes all Pd-*.app bundles (e.g. iterate over
"$APPDIR"/Pd-*.app and rm -rf each if it exists, or use find -maxdepth 1 -name
'Pd-*.app' -exec rm -rf {} \;) to ensure older/newer versions are removed.
Locate the hard-coded removal in the script (search for the literal sudo rm -rf
"$APPDIR/Pd-0.56-3.app") and update it there; keep quoting to handle spaces and
avoid accidental glob expansion when no matches.
🪄 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
Run ID: 588c7c30-4d63-4bed-9905-bec0f4577b26
⛔ Files ignored due to path filters (1)
website/assets/images/app-icon-pd-60x60@2x.pngis excluded by!**/*.png
📒 Files selected for processing (8)
ee/maintained-apps/ingesters/homebrew/external_refs/main.goee/maintained-apps/ingesters/homebrew/external_refs/version_shortener.goee/maintained-apps/inputs/homebrew/pd.jsonee/maintained-apps/inputs/homebrew/scripts/pd-install.shee/maintained-apps/outputs/apps.jsonee/maintained-apps/outputs/pd/darwin.jsonfrontend/pages/SoftwarePage/components/icons/Pd.tsxfrontend/pages/SoftwarePage/components/icons/index.ts
| APP_NAME=$(basename "$APP_BUNDLE") | ||
| # copy to the applications folder | ||
| quit_and_track_application 'org.puredata.pd.pd-gui' | ||
| if [ -d "$APPDIR/$APP_NAME" ]; then | ||
| sudo mv "$APPDIR/$APP_NAME" "$TMPDIR/$APP_NAME.bkp" | ||
| fi | ||
| sudo cp -R "$APP_BUNDLE" "$APPDIR" |
There was a problem hiding this comment.
Versioned bundle names will leave stale Pd installs after upgrades.
The replacement path only targets /Applications/$APP_NAME for the new version name, so prior Pd-*.app versions remain installed. That can keep old inventory rows and prevent hosts from ever evaluating as fully patched.
Suggested fix
APP_NAME=$(basename "$APP_BUNDLE")
# copy to the applications folder
quit_and_track_application 'org.puredata.pd.pd-gui'
-if [ -d "$APPDIR/$APP_NAME" ]; then
- sudo mv "$APPDIR/$APP_NAME" "$TMPDIR/$APP_NAME.bkp"
-fi
+# Remove previously installed versioned Pd bundles (e.g. Pd-0.56-2.app).
+while IFS= read -r existing_pd_app; do
+ [ -d "$existing_pd_app" ] || continue
+ sudo mv "$existing_pd_app" "$TMPDIR/$(basename "$existing_pd_app").bkp"
+done < <(find "$APPDIR" -maxdepth 1 -type d -name "Pd-*.app")
+
sudo cp -R "$APP_BUNDLE" "$APPDIR"
hdiutil detach "$MOUNT_POINT" || true
relaunch_application 'org.puredata.pd.pd-gui'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| APP_NAME=$(basename "$APP_BUNDLE") | |
| # copy to the applications folder | |
| quit_and_track_application 'org.puredata.pd.pd-gui' | |
| if [ -d "$APPDIR/$APP_NAME" ]; then | |
| sudo mv "$APPDIR/$APP_NAME" "$TMPDIR/$APP_NAME.bkp" | |
| fi | |
| sudo cp -R "$APP_BUNDLE" "$APPDIR" | |
| APP_NAME=$(basename "$APP_BUNDLE") | |
| # copy to the applications folder | |
| quit_and_track_application 'org.puredata.pd.pd-gui' | |
| # Remove previously installed versioned Pd bundles (e.g. Pd-0.56-2.app). | |
| while IFS= read -r existing_pd_app; do | |
| [ -d "$existing_pd_app" ] || continue | |
| sudo mv "$existing_pd_app" "$TMPDIR/$(basename "$existing_pd_app").bkp" | |
| done < <(find "$APPDIR" -maxdepth 1 -type d -name "Pd-*.app") | |
| sudo cp -R "$APP_BUNDLE" "$APPDIR" |
🤖 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/inputs/homebrew/scripts/pd-install.sh` around lines 117 -
123, The script only handles the exact APP_NAME, leaving older versioned bundles
(e.g., Pd-1.0.app, Pd-1.1.app) behind; before copying, derive a stable prefix
from APP_NAME (e.g., PREFIX="${APP_NAME%%-*}" or strip version suffix) and
locate all existing bundles in APPDIR that start with that prefix (use
APPDIR/"${PREFIX}"*.app), then quit via quit_and_track_application and move or
remove those matches to TMPDIR as backups (instead of only moving
"$APPDIR/$APP_NAME"), ensuring all prior Pd installs are cleaned up before sudo
cp -R "$APP_BUNDLE" "$APPDIR".
| "2eac86b0": "#!/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/Pd-0.56-3.app\"\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.puredata.pd.pd-gui.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.puredata.pd.pd-gui.savedState'\n", | ||
| "8a005b0c": "#!/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\n# Pd's download is a .zip that contains a .dmg, which in turn contains the .app.\n# The app folder name carries the version (e.g. \"Pd-0.56-3.app\"), so unzip\n# first, then mount the embedded DMG and copy whichever .app it contains. This\n# keeps the script version-agnostic across Homebrew bumps.\nEXTRACT_DIR=$(mktemp -d /tmp/pd_extract_XXXXXX)\nunzip -q \"$INSTALLER_PATH\" -d \"$EXTRACT_DIR\"\nDMG_PATH=$(find \"$EXTRACT_DIR\" -maxdepth 2 -name \"*.dmg\" | head -1)\nif [ -z \"$DMG_PATH\" ]; then\n echo \"No DMG found inside the Pd archive\" >&2\n exit 1\nfi\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$DMG_PATH\" || exit 1\nAPP_BUNDLE=$(find \"$MOUNT_POINT\" -maxdepth 1 -name \"*.app\" | head -1)\nif [ -z \"$APP_BUNDLE\" ]; then\n echo \"No .app found inside the Pd DMG\" >&2\n hdiutil detach \"$MOUNT_POINT\" || true\n exit 1\nfi\nAPP_NAME=$(basename \"$APP_BUNDLE\")\n# copy to the applications folder\nquit_and_track_application 'org.puredata.pd.pd-gui'\nif [ -d \"$APPDIR/$APP_NAME\" ]; then\n\tsudo mv \"$APPDIR/$APP_NAME\" \"$TMPDIR/$APP_NAME.bkp\"\nfi\nsudo cp -R \"$APP_BUNDLE\" \"$APPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\nrelaunch_application 'org.puredata.pd.pd-gui'\n" |
There was a problem hiding this comment.
Embedded uninstall script removes only one versioned app path.
sudo rm -rf "$APPDIR/Pd-0.56-3.app" won’t remove older/newer Pd-*.app directories, so uninstall can leave Pd installed.
Suggested fix (script body before JSON escaping)
-sudo rm -rf "$APPDIR/Pd-0.56-3.app"
+find "$APPDIR" -maxdepth 1 -type d -name "Pd-*.app" -exec sudo rm -rf {} +🤖 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/pd/darwin.json` around lines 19 - 20, The
uninstall step currently runs sudo rm -rf "$APPDIR/Pd-0.56-3.app" which only
removes one hard-coded version; replace that with logic that removes all
Pd-*.app bundles (e.g. iterate over "$APPDIR"/Pd-*.app and rm -rf each if it
exists, or use find -maxdepth 1 -name 'Pd-*.app' -exec rm -rf {} \;) to ensure
older/newer versions are removed. Locate the hard-coded removal in the script
(search for the literal sudo rm -rf "$APPDIR/Pd-0.56-3.app") and update it
there; keep quoting to handle spaces and avoid accidental glob expansion when no
matches.
Add support for Pd (Pure Data) on macOS: new Homebrew input manifest and installer script, outputs and apps entry, frontend icon and image, and a version transformer.
Summary by CodeRabbit