Fix misleading keepalive log messages and cache DateFormatters#434
Fix misleading keepalive log messages and cache DateFormatters#434guglielmofonda wants to merge 3 commits intosteipete:mainfrom
Conversation
- AugmentSessionKeepalive: log messages claimed "every 5 minutes" and "2 minutes" but the actual intervals were 60s (1 min) each; now computed dynamically from the real values so they can never drift - CursorStatusProbe, ClaudeUsageFetcher, FactoryStatusProbe, UsageFormatter: DateFormatter was re-allocated on every call inside formatResetDate / creditEvent helpers; replaced with nonisolated(unsafe) static let singletons initialized once at first use
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae8d9e8c53
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| nonisolated(unsafe) private static let resetDateFormatter: DateFormatter = { | ||
| let f = DateFormatter() | ||
| f.dateFormat = "MMM d 'at' h:mma" | ||
| f.locale = Locale(identifier: "en_US_POSIX") | ||
| return f |
There was a problem hiding this comment.
Preserve timezone updates when caching reset date formatter
This singleton DateFormatter now captures the process default timezone once and reuses it forever, so long-lived app sessions can show stale reset times after a system timezone change (travel, DST, manual timezone change) until restart. Before this commit, constructing a formatter per call picked up the current timezone each time. The same caching pattern was added in ClaudeUsageFetcher and FactoryStatusProbe, so all reset labels can drift; use .autoupdatingCurrent timezone (and locale where needed) or keep formatter creation thread/timezone-scoped.
Useful? React with 👍 / 👎.
When "Show time until reset" is enabled in Settings → Display, a compact countdown (e.g. "72% · 28m" or "72% · 2h 5m") appears next to the percentage in the menu bar. It picks the nearest upcoming reset across the primary and secondary quota windows. - MenuBarDisplayText: add timeUntilResetText() formatter - StatusItemController+Animation: append countdown to menuBarDisplayText - StatusItemController: start/stop a 60-second Timer so the label ticks down every minute without waiting for a data refresh - SettingsStoreState / SettingsStore / SettingsStore+Defaults: persist the new `menuBarShowsTimeUntilReset` boolean via UserDefaults - PreferencesDisplayPane: add toggle under "Menu bar shows percent" (disabled + faded when text mode is off, since the countdown is invisible in icon-only mode)
Summary
Fix misleading log messages in
AugmentSessionKeepalive: startup logs claimed"every 5 minutes"and"2 minutes"but the actual intervals were both60s(1 min). The parenthetical labels were stale copy-paste. Now computed dynamically from the real values so they can never drift.Cache
DateFormatteras static singletons:DateFormatteris expensive to initialize (loads locale, calendar, and timezone data on each call). Five methods across four files were allocating a fresh instance on every invocation:CursorStatusProbe.formatResetDateClaudeUsageFetcher.formatResetDateFactoryStatusProbe.formatResetDate(insideFactoryStatusSnapshot)UsageFormatter.creditEventSummaryandcreditEventCompactAll replaced with
nonisolated(unsafe) private static letsingletons — initialized once, reused on every subsequent call.nonisolated(unsafe)is the Swift 6 idiom for opting out of the concurrency check when safety can be reasoned about manually (formatter is configured at init and never mutated after).Test plan
swift buildpasses with no errors or warnings