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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,12 @@ removes its firewall rules, unregisters its privileged helper, and then removes
the application:

```bash
sudo "/Applications/PAIR.app/Contents/Resources/installer-tools/uninstall-macos.sh"
sudo "/Applications/NVIDIA PAIR.app/Contents/Resources/installer-tools/uninstall-macos.sh"
```

Add `--purge` to remove your data as well. Dragging PAIR to the Trash instead
An install from before the app was renamed is still called `PAIR.app`; use
`/Applications/PAIR.app` in the path instead. Add `--purge` to remove your data
as well. Dragging PAIR to the Trash instead
leaves the privileged helper registered, so use the uninstaller.

Your data means settings, logs, cluster identity and certificates, and any engine
Expand Down
20 changes: 13 additions & 7 deletions desktop/electron-builder.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,16 @@ const osSegment =
: null

const output = osSegment ? `release/${pkg.version}/${osSegment}` : `release/${pkg.version}`
// Only Windows uses the display name as the packaging product name (drives NSIS
// branding; the install dir and executable are pinned to APP_EXECUTABLE_NAME via
// win.executableName). macOS and Linux keep the technical name so the app bundle
// (`PAIR.app`) and Linux install dir (`/opt/PAIR`) stay stable — existing
// generated CLI launchers embed those absolute paths.
const packagingProductName = osSegment === 'windows' ? APP_DISPLAY_NAME : APP_EXECUTABLE_NAME
// Windows and macOS use the display name as the packaging product name. On
// Windows it drives the NSIS branding; the install dir and executable are pinned
// to APP_EXECUTABLE_NAME via win.executableName. On macOS it sets CFBundleName,
// and mac.executableName names the bundle, `NVIDIA PAIR.app`: those are what
// Finder, the Dock, Launchpad, Spotlight, and the menu bar show, and
// CFBundleDisplayName alone is ignored there. Linux keeps the technical name so
// its install dir stays `/opt/PAIR`, which the packaged `/usr/bin/nvpair`
// wrapper embeds.
const packagingProductName =
osSegment === 'windows' || osSegment === 'mac' ? APP_DISPLAY_NAME : APP_EXECUTABLE_NAME

function packagingPlatform(): SupportedPlatform {
const platform =
Expand Down Expand Up @@ -393,7 +397,9 @@ const config: Configuration = {
afterRemove: 'scripts/build/linux/after-remove.sh'
},
mac: {
executableName: APP_EXECUTABLE_NAME,
// electron-builder names the bundle after the executable, so this is
// what makes it `NVIDIA PAIR.app`; see packagingProductName.
executableName: APP_DISPLAY_NAME,
extendInfo: {
CFBundleDisplayName: APP_DISPLAY_NAME
},
Expand Down
23 changes: 19 additions & 4 deletions desktop/scripts/build/macos/uninstall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,18 @@ case "${1:-}" in
;;
esac

APP_PATH="/Applications/PAIR.app"
# The bundle this script ships in, three levels above Contents/Resources/
# installer-tools. It is found rather than named because installs exist under
# two names: the bundle is `NVIDIA PAIR.app`, and one installed while it was
# still `PAIR.app` keeps that name, since Squirrel.Mac updates a bundle in place.
APP_PATH="$(cd "$(dirname "$0")/../../.." && pwd -P)"
case "$APP_PATH" in
*.app) ;;
*)
echo "run this from inside the app bundle: <app>.app/Contents/Resources/installer-tools/$(basename "$0")" >&2
exit 2
;;
esac
# Bundle id used to key the macOS framework state cleaned up below (the .dmg
# leaves no pkg receipt to forget).
PACKAGE_ID="com.nvidia.nvpair"
Expand All @@ -50,11 +61,15 @@ fi
APP_SUPPORT="$target_home/Library/Application Support"

echo "Stopping NVIDIA PAIR processes..."
# The app process is named by the bundle's own executable, read rather than
# assumed for the same reason APP_PATH is.
APP_EXECUTABLE="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$APP_PATH/Contents/Info.plist" 2>/dev/null || true)"
if [ -n "$APP_EXECUTABLE" ]; then
pkill -TERM -x "$APP_EXECUTABLE" 2>/dev/null || true
fi
# Keep this list in sync with MODULAR_RUNTIME_BINARIES and
# MODULAR_BUNDLED_BINARIES in src/shared/constants/modular-binaries.ts, plus the
# Electron app process.
# MODULAR_BUNDLED_BINARIES in src/shared/constants/modular-binaries.ts.
for proc in \
"PAIR" \
"nvpair-tui" \
"nvpair-proxy" \
"ollama-proxy" \
Expand Down
2 changes: 1 addition & 1 deletion scripts/wipe-app-data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#
# Explicit exclusions (never add): ~/.ollama, ~/.lmstudio, external engine
# installs, and the application install tree (Program Files / /opt/PAIR /
# PAIR.app).
# the macOS app bundle).
# ---------------------------------------------------------------------------
set -uo pipefail

Expand Down
Loading