From 1daecfa4b0cb5101f9fb1cd6b01a8d877155bab6 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 2 Jun 2026 19:30:06 -0500 Subject: [PATCH] fix(desktop): write Dock tile as a file-reference URL The Dock stores persistent-apps as type-15 file:// URLs; the type-0/raw-path tile we wrote was silently dropped on the next Dock restart (so the pin never took, yet we'd stamped the marker and never retried). Use pathToFileURL + type 15 and flush prefs through cfprefsd before `killall Dock`. Verified end-to-end on a packaged build: move -> adopt -> Dock tile lands as file:///Applications/Hermes.app/. --- apps/desktop/electron/main.cjs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/desktop/electron/main.cjs b/apps/desktop/electron/main.cjs index cd8c6a08b82..71aded3fd72 100644 --- a/apps/desktop/electron/main.cjs +++ b/apps/desktop/electron/main.cjs @@ -4047,6 +4047,11 @@ function maybePinToDock() { } if (!bundle) return + // The Dock stores tiles as file-reference URLs (type 15), e.g. + // file:///Applications/Hermes.app/ -- NOT a raw POSIX path. A type-0/raw-path + // tile is silently dropped when the Dock rewrites persistent-apps on restart. + const url = pathToFileURL(bundle.endsWith('/') ? bundle : `${bundle}/`).href + const done = note => { try { fs.writeFileSync(marker, JSON.stringify({ bundle, pinnedAt: new Date().toISOString(), ...note }) + '\n') @@ -4060,20 +4065,23 @@ function maybePinToDock() { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }) - if (apps.includes(bundle)) return done({ alreadyPresent: true }) + if (apps.includes(url)) return done({ alreadyPresent: true }) } catch { // persistent-apps may not exist yet; -array-add creates it } const tile = 'tile-datafile-data' + - `_CFURLString${bundle}_CFURLStringType0` + + `_CFURLString${url}_CFURLStringType15` + '' try { execFileSync('defaults', ['write', 'com.apple.dock', 'persistent-apps', '-array-add', tile], { stdio: 'ignore' }) + // Flush the write through cfprefsd before restarting the Dock, otherwise the + // Dock reloads stale prefs and our tile is lost in the race. + execFileSync('defaults', ['read', 'com.apple.dock', 'persistent-apps'], { stdio: 'ignore' }) execFileSync('killall', ['Dock'], { stdio: 'ignore' }) done() - rememberLog(`[install] pinned to Dock: ${bundle}`) + rememberLog(`[install] pinned to Dock: ${url}`) } catch (err) { rememberLog(`[install] Dock pin skipped: ${err.message}`) }