mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-11 09:34:45 +00:00
Merge pull request #867 from marcreynolds/feat/menubar-degraded-device-indicator
feat(menubar): mark badge when a paired device is unreachable in combined scope
This commit is contained in:
commit
dc3ea24b1d
3 changed files with 86 additions and 1 deletions
|
|
@ -285,6 +285,17 @@ final class AppStore {
|
|||
return cache[menubarCombinedKey]?.payload.combined?.combined
|
||||
}
|
||||
|
||||
/// `(reachable, total)` only when combined scope is active and fewer paired
|
||||
/// devices reported than are paired — i.e. the badge total is degraded to
|
||||
/// the reachable subset (a peer is asleep/off-network this cycle). The badge
|
||||
/// shows this so a momentary drop to the local figure reads as "peer
|
||||
/// unreachable", not a glitch. `nil` when every paired device reported (or
|
||||
/// there is only one), and under local scope.
|
||||
var menubarBadgeDeviceShortfall: (reachable: Int, total: Int)? {
|
||||
guard let totals = menubarBadgeCombined, totals.reachableCount < totals.deviceCount else { return nil }
|
||||
return (totals.reachableCount, totals.deviceCount)
|
||||
}
|
||||
|
||||
/// Refresh the payloads the badge renders for `period`: always the local
|
||||
/// figure, plus the combined cross-device total when combined scope is
|
||||
/// active. Combined is best-effort — a slow or unreachable peer degrades to
|
||||
|
|
|
|||
|
|
@ -1058,10 +1058,27 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate, NSM
|
|||
textAttrs[.foregroundColor] = NSColor.secondaryLabelColor
|
||||
}
|
||||
composed.append(NSAttributedString(string: valueText, attributes: textAttrs))
|
||||
|
||||
// Combined scope, but a paired device didn't report this cycle: append
|
||||
// a dimmed "reachable/total" so the reduced total reads as "peer
|
||||
// unreachable" rather than a glitch (mirrors the popover's device list).
|
||||
if let shortfall = store.menubarBadgeDeviceShortfall {
|
||||
let marker = " · \(shortfall.reachable)/\(shortfall.total)"
|
||||
let markerAttrs: [NSAttributedString.Key: Any] = [
|
||||
.font: font,
|
||||
.baselineOffset: -1.0,
|
||||
.foregroundColor: NSColor.secondaryLabelColor,
|
||||
]
|
||||
composed.append(NSAttributedString(string: marker, attributes: markerAttrs))
|
||||
}
|
||||
}
|
||||
|
||||
button.attributedTitle = composed
|
||||
button.toolTip = "CodeBurn \(menubarPeriod.menubarMetricLabel)"
|
||||
if let shortfall = store.menubarBadgeDeviceShortfall {
|
||||
button.toolTip = "CodeBurn \(menubarPeriod.menubarMetricLabel) · \(shortfall.reachable) of \(shortfall.total) devices reporting"
|
||||
} else {
|
||||
button.toolTip = "CodeBurn \(menubarPeriod.menubarMetricLabel)"
|
||||
}
|
||||
|
||||
persistBadgeStatusFile()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,6 +234,63 @@ struct AppStoreRefreshRecoveryTests {
|
|||
#expect(store.menubarBadgeCombined?.cost == 75)
|
||||
}
|
||||
|
||||
@Test("badge reports a device shortfall when a paired peer is unreachable")
|
||||
func menubarBadgeReportsDeviceShortfall() {
|
||||
let store = AppStore()
|
||||
store.suppressRefreshesForTesting()
|
||||
let period = store.menubarPeriod
|
||||
// Combined payload where only 1 of 2 paired devices reported this cycle
|
||||
// (the peer is asleep/off-network), so the aggregate is degraded to local.
|
||||
let degraded = CombinedUsage(
|
||||
perDevice: [],
|
||||
combined: CombinedUsageTotals(
|
||||
cost: 30,
|
||||
calls: 3,
|
||||
sessions: 2,
|
||||
inputTokens: 100,
|
||||
outputTokens: 50,
|
||||
cacheCreateTokens: 10,
|
||||
cacheReadTokens: 20,
|
||||
totalTokens: 180,
|
||||
deviceCount: 2,
|
||||
reachableCount: 1
|
||||
)
|
||||
)
|
||||
store.setCachedPayloadForTesting(
|
||||
menubarPayload(cost: 30, combined: degraded),
|
||||
scope: .combined,
|
||||
period: period,
|
||||
provider: .all,
|
||||
fetchedAt: Date()
|
||||
)
|
||||
store.selectedScope = .combined
|
||||
|
||||
let shortfall = store.menubarBadgeDeviceShortfall
|
||||
#expect(shortfall?.reachable == 1)
|
||||
#expect(shortfall?.total == 2)
|
||||
}
|
||||
|
||||
@Test("badge reports no shortfall when every paired device reports")
|
||||
func menubarBadgeNoShortfallWhenAllReachable() {
|
||||
let store = AppStore()
|
||||
store.suppressRefreshesForTesting()
|
||||
let period = store.menubarPeriod
|
||||
// combinedUsage() carries deviceCount == reachableCount == 1.
|
||||
store.setCachedPayloadForTesting(
|
||||
menubarPayload(cost: 30, combined: combinedUsage(cost: 30)),
|
||||
scope: .combined,
|
||||
period: period,
|
||||
provider: .all,
|
||||
fetchedAt: Date()
|
||||
)
|
||||
store.selectedScope = .combined
|
||||
#expect(store.menubarBadgeDeviceShortfall == nil)
|
||||
|
||||
// Local scope never reports a shortfall.
|
||||
store.selectedScope = .local
|
||||
#expect(store.menubarBadgeDeviceShortfall == nil)
|
||||
}
|
||||
|
||||
@Test("menubar badge falls back to local when no combined payload is cached")
|
||||
func menubarBadgeFallsBackWhenCombinedMissing() {
|
||||
let store = AppStore()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue