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.
This commit is contained in:
iamtoruk 2026-04-21 13:05:56 -07:00
parent 90aa342a34
commit 6ed0799b36

View file

@ -30,11 +30,21 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
private let store = AppStore()
let updateChecker = UpdateChecker()
private var refreshTask: Task<Void, Never>?
/// 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()