From 6d24f40457a1adbae2bea30a2ee9bc5b6b774c63 Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Thu, 12 Feb 2026 09:07:07 -0800 Subject: [PATCH] fix(desktop): fix dev protocol plist patching to prevent deep link collisions The patch-dev-protocol script had bugs that left Electron.app with the default com.github.Electron bundle ID, causing macOS Launch Services to treat all dev worktrees as the same app and route deep links to the wrong instance. - Delete existing CFBundleURLTypes before re-adding to prevent stale/duplicate entries - Validate both bundle ID and scheme in "already patched" check - Stop swallowing errors on PlistBuddy commands so failures surface --- apps/desktop/scripts/patch-dev-protocol.ts | 34 +++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/desktop/scripts/patch-dev-protocol.ts b/apps/desktop/scripts/patch-dev-protocol.ts index 67588ce40e6..285345f3d7b 100644 --- a/apps/desktop/scripts/patch-dev-protocol.ts +++ b/apps/desktop/scripts/patch-dev-protocol.ts @@ -1,7 +1,10 @@ #!/usr/bin/env bun /** - * Patches the development Electron.app's Info.plist to register - * the superset-dev:// URL scheme for deep linking. + * Patches the development Electron.app's Info.plist to register a + * workspace-specific URL scheme (superset-{workspace}://) for deep linking. + * + * Each worktree gets a unique bundle ID and protocol scheme so macOS Launch + * Services treats them as distinct apps and routes deep links correctly. * * This is needed because on macOS, app.setAsDefaultProtocolClient() * only works when the app is packaged. In development, we need to @@ -45,14 +48,18 @@ if (!existsSync(PLIST_PATH)) { process.exit(0); } -// Check if already patched +// Check if already correctly patched (right bundle ID + right scheme) try { - const result = execSync( + const currentBundleId = execSync( + `/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${PLIST_PATH}" 2>/dev/null`, + { encoding: "utf-8" }, + ).trim(); + const currentScheme = execSync( `/usr/libexec/PlistBuddy -c "Print :CFBundleURLTypes:0:CFBundleURLSchemes:0" "${PLIST_PATH}" 2>/dev/null`, { encoding: "utf-8" }, ).trim(); - if (result === PROTOCOL_SCHEME) { + if (currentBundleId === BUNDLE_ID && currentScheme === PROTOCOL_SCHEME) { console.log( `[patch-dev-protocol] ${PROTOCOL_SCHEME}:// already registered`, ); @@ -64,13 +71,18 @@ try { console.log(`[patch-dev-protocol] Registering ${PROTOCOL_SCHEME}:// scheme...`); -// Set unique bundle ID to avoid conflicts with other Electron apps +// Set unique bundle ID so macOS treats each worktree's Electron as a distinct app +execSync( + `/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier ${BUNDLE_ID}" "${PLIST_PATH}"`, +); + +// Remove any existing URL types to avoid stale/duplicate entries from previous patches try { execSync( - `/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier ${BUNDLE_ID}" "${PLIST_PATH}"`, + `/usr/libexec/PlistBuddy -c "Delete :CFBundleURLTypes" "${PLIST_PATH}" 2>/dev/null`, ); } catch { - // Ignore errors + // Doesn't exist yet, that's fine } // Add URL scheme to Info.plist @@ -84,11 +96,7 @@ const commands = [ ]; for (const cmd of commands) { - try { - execSync(`/usr/libexec/PlistBuddy -c "${cmd}" "${PLIST_PATH}" 2>/dev/null`); - } catch { - // Ignore errors (e.g., key already exists) - } + execSync(`/usr/libexec/PlistBuddy -c "${cmd}" "${PLIST_PATH}"`); } // Register with Launch Services