Merge pull request #140 from getagentseal/fix/menubar-stability

Fix menubar crashes and add reliable auto-refresh
This commit is contained in:
Resham Joshi 2026-04-23 12:13:55 -07:00 committed by GitHub
commit ed3abce4f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 67 additions and 3 deletions

View file

@ -48,6 +48,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
observeStore()
startRefreshLoop()
setupWakeObservers()
setupDistributedNotificationListener()
installLaunchAgentIfNeeded()
Task { await updateChecker.checkIfNeeded() }
}
@ -69,6 +71,68 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
}
}
private func setupDistributedNotificationListener() {
DistributedNotificationCenter.default().addObserver(
forName: NSNotification.Name("com.codeburn.refresh"),
object: nil,
queue: .main
) { [weak self] _ in
Task { @MainActor in self?.forceRefresh() }
}
}
private func installLaunchAgentIfNeeded() {
let fm = FileManager.default
let agentName = "com.codeburn.refresh.plist"
let home = fm.homeDirectoryForCurrentUser.path
let destPath = "\(home)/Library/LaunchAgents/\(agentName)"
let plist = """
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.codeburn.refresh</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/osascript</string>
<string>-l</string>
<string>JavaScript</string>
<string>-e</string>
<string>ObjC.import("Foundation"); $.NSDistributedNotificationCenter.defaultCenter.postNotificationNameObjectUserInfoDeliverImmediately("com.codeburn.refresh", $(), $(), true)</string>
</array>
<key>StartInterval</key>
<integer>15</integer>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
"""
do {
let existing = try? String(contentsOfFile: destPath, encoding: .utf8)
if existing == plist { return }
try fm.createDirectory(atPath: "\(home)/Library/LaunchAgents", withIntermediateDirectories: true)
try plist.write(toFile: destPath, atomically: true, encoding: .utf8)
let unload = Process()
unload.launchPath = "/bin/launchctl"
unload.arguments = ["unload", destPath]
try? unload.run()
unload.waitUntilExit()
let load = Process()
load.launchPath = "/bin/launchctl"
load.arguments = ["load", destPath]
try load.run()
load.waitUntilExit()
} catch {
NSLog("CodeBurn: LaunchAgent setup failed: \(error)")
}
}
private func forceRefresh() {
Task {
await store.refreshQuietly(period: .today)

View file

@ -225,7 +225,7 @@ private func computeHistoryStats(history: [DailyHistoryEntry]) -> HistoryStats {
}()
let now = Date()
let today = calendar.startOfDay(for: now)
let costByDate = Dictionary(uniqueKeysWithValues: history.map { ($0.date, $0.cost) })
let costByDate = Dictionary(history.map { ($0.date, $0.cost) }, uniquingKeysWith: +)
let lastWeekStart = calendar.date(byAdding: .day, value: -6, to: today)
let priorWeekStart = calendar.date(byAdding: .day, value: -13, to: today)

View file

@ -399,7 +399,7 @@ private func buildTrendBars(from days: [DailyHistoryEntry]) -> [TrendBar] {
f.timeZone = .current
return f
}()
let entryByDate = Dictionary(uniqueKeysWithValues: days.map { ($0.date, $0) })
let entryByDate = Dictionary(days.map { ($0.date, $0) }, uniquingKeysWith: { _, new in new })
let today = calendar.startOfDay(for: Date())
let todayKey = formatter.string(from: today)
@ -837,7 +837,7 @@ private func computeAllStats(payload: MenubarPayload) -> AllStats {
peakDaySpend = ""
}
let costByDate = Dictionary(uniqueKeysWithValues: history.map { ($0.date, $0.cost) })
let costByDate = Dictionary(history.map { ($0.date, $0.cost) }, uniquingKeysWith: +)
var currentStreak = 0
for offset in 0..<400 {