From 6ed0799b362c32bf567e362e8296801ed057c571 Mon Sep 17 00:00:00 2001 From: iamtoruk Date: Tue, 21 Apr 2026 13:05:56 -0700 Subject: [PATCH] fix(menubar): opt out of App Nap so the refresh loop keeps ticking Confirmed in the system log: while the menubar icon sits idle in the background, macOS flips _kLSApplicationWouldBeTerminatedByTALKey to 1, which is the Automatic Termination and App Nap subsystem declaring the app a suspend candidate. Once that happens the 15s refresh Task's sleep stretches arbitrarily, so the status bar label freezes until the user clicks the icon (which triggers NSApp.activate and wakes everything up). Hold a ProcessInfo.beginActivity handle for the life of the app with .userInitiated + .automaticTerminationDisabled + .suddenTerminationDisabled so macOS leaves the app alone. Released implicitly when the app exits. --- mac/Sources/CodeBurnMenubar/CodeBurnApp.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift b/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift index c70c67c..501dcd6 100644 --- a/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift +++ b/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift @@ -30,11 +30,21 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { private let store = AppStore() let updateChecker = UpdateChecker() private var refreshTask: Task? + /// Held for the lifetime of the app to opt out of App Nap and Automatic Termination. + /// Without this the 15s refresh Task gets suspended whenever the user is interacting with + /// another app, and the status bar label freezes until they click the menubar icon (which + /// calls NSApp.activate and wakes the app back up). + private var backgroundActivity: NSObjectProtocol? func applicationDidFinishLaunching(_ notification: Notification) { // Menubar accessory -- no Dock icon, no app switcher entry. NSApp.setActivationPolicy(.accessory) + backgroundActivity = ProcessInfo.processInfo.beginActivity( + options: [.userInitiated, .automaticTerminationDisabled, .suddenTerminationDisabled], + reason: "CodeBurn menubar polls AI coding cost every 15 seconds while idle in the background." + ) + restorePersistedCurrency() setupStatusItem() setupPopover()