diff --git a/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift b/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift index befaf027..f33f0516 100644 --- a/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift +++ b/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift @@ -90,9 +90,15 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate, NSM } func applicationWillFinishLaunching(_ notification: Notification) { - // Set accessory policy before the app's focus chain forms. On macOS Tahoe - // (26.x), setting it after didFinishLaunching causes ghost status items - // because the policy gets baked into the initial focus chain. + // Belt-and-suspenders for dev runs only: packaged builds ship + // LSUIElement=true (package-app.sh / build-local.sh), so LaunchServices + // starts the process at .accessory before main() runs and this call is + // a measured no-op there (returns false, no state change — #868 + // analysis). What actually matters is that the policy NEVER + // transitions while a live NSStatusItem exists: the .regular → + // .accessory dance from #147 is what plausibly caused the ghost item + // that 85b5728 fixed. Keep the policy pinned; see the activate() call + // in applicationDidFinishLaunching for the other half of the story. NSApp.setActivationPolicy(.accessory) } @@ -120,6 +126,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate, NSM // interaction (popover open, wake) refreshes immediately. restorePersistedCurrency() + // #868 experiment: restore only the activation half of the #147 fix. + // Packaged builds ship LSUIElement=true, so the policy is .accessory + // before main() runs and never transitions (the transition is what + // plausibly caused the ghost item). Accessory apps can still activate, + // which registers the app with the window server before the status + // item is created - the effect #147 actually needed for #146. + NSApp.activate(ignoringOtherApps: true) setupStatusItem() setupPopover() observeStore()