Commit graph

155 commits

Author SHA1 Message Date
iamtoruk
51b90aa1a5 feat(menubar): badge falls back to launchd status file
refreshStatusButton now uses the fresher of the in-memory payload and
the file written by the LaunchAgent, so the menubar number advances
within ~30s even if the in-app loop is dead.
2026-05-30 00:48:12 -07:00
iamtoruk
3f4298103b feat(menubar): write refresh script on launch and period change 2026-05-30 00:46:54 -07:00
iamtoruk
1269406c7a feat(menubar): static LaunchAgent runs menubar-refresh.sh
Migrate off the osascript distributed-notification form (dropped by
napped apps) to a static /bin/sh runner. The plist no longer encodes
period, so it migrates once; period changes rewrite only the script.
2026-05-30 00:45:45 -07:00
iamtoruk
1341b626a2 feat(menubar): generate self-contained menubar-refresh.sh
The script runs the CLI for the badge period and atomically writes
menubar-status.json, so a static LaunchAgent can refresh the badge
out of process.
2026-05-30 00:40:03 -07:00
iamtoruk
be7b8278c5 feat(menubar): add CodeburnCLI.scriptEnvironment for shell-script embedding
Exposes the validated argv and augmented PATH so the LaunchAgent runner
script can be generated without re-resolving the binary or PATH.
2026-05-30 00:10:29 -07:00
iamtoruk
bdbd7b19f6 feat(menubar): add MenubarStatusCache read side for badge backstop 2026-05-30 00:01:07 -07:00
iamtoruk
75edff64ec fix(menubar): popover-open always force-recovers current key
Opening the popover now unconditionally restarts a dead timer and
clears stuck loading bookkeeping before force-fetching, so a user
looking at a stuck tab always recovers within one CLI round-trip.
2026-05-29 23:51:48 -07:00
iamtoruk
ea64dca52e fix(menubar): keep refresh timer alive across sleep
The sleep handler tore down the DispatchSource timer; a missed wake
notification then left it nil forever, stranding the refresh loop.
Cancel only in-flight tasks and let the kernel-paused timer resume.
2026-05-29 23:46:16 -07:00
iamtoruk
372681cae2 fix(menubar): recover from stuck loading when in-flight entry is orphaned
A quiet refresh torn down across sleep/wake (or a generation reset) can
leave an orphaned inFlightKeys entry for the current key. The stuck-loading
recovery guard bailed whenever any in-flight entry existed, so the popover's
retry loop no-oped forever and the spinner ("Loading Today...") never
cleared — observed on a long-lived instance that crossed the midnight day
rollover.

Clear stale loading/in-flight state via the existing watchdog before the
in-flight guard, so an orphaned entry can no longer trap recovery. A healthy
in-flight fetch (younger than the watchdog) is still respected.
2026-05-28 14:06:13 -07:00
iamtoruk
11b3e1be58 fix(menubar): re-check CLI version on every update cycle 2026-05-27 06:35:00 -07:00
iamtoruk
af99516633 feat(menubar): show CLI update banner when a newer version is available 2026-05-27 06:27:49 -07:00
iamtoruk
3751b3381c fix(menubar): add watchdog backoff, remove dead RefreshBackoff code
PR #393 accidentally deleted the RefreshBackoff integration from PR #388,
leaving RefreshBackoff.swift as dead code and tests calling nonexistent
methods. Delete the dead code and fix the broken test target.

Add exponential backoff to the loading watchdog (8s, 16s, 32s... up to
60s, max 6 attempts) so it stops hammering the CLI when it's unavailable.
After exhausting retries, show an error overlay with a Retry button.

Fix recoverFromStuckLoading to skip recovery when a fetch is already
in-flight (avoids killing healthy fetches via generation bump).

Fix selectedDay to return nil for multi-day selections, and pass days
through startInteractiveSelectionRefresh so the cache key matches
currentKey.
2026-05-27 04:38:42 -07:00
iamtoruk
ac35746209 fix(menubar): recover from stuck loading state
Commit 5800179 (multi-day calendar) accidentally removed stuck-loading
recovery. Re-add an 8-second watchdog loop in MenuBarContent that calls
recoverFromStuckLoading(). Change inFlightKeys from Set to timestamped
Dict so the watchdog can detect orphaned quiet-refresh entries. Stop
nuking payloadRefreshGeneration in the watchdog (it was killing healthy
in-flight fetches). Bump Package.swift platform to macOS 15 to match
NSAttributedString(attachment:) usage.
2026-05-27 04:06:48 -07:00
Resham Joshi
ce043631ed
Add icon-only menubar display mode (#396)
Some checks are pending
CI / semgrep (push) Waiting to run
Adds "Icon Only" option to the Metric picker in Settings. When
selected, the menubar shows only the flame icon without any cost
or token text. Flame tinting for quota/budget alerts still works.
2026-05-24 18:05:15 -07:00
Resham Joshi
5800179da9
Add multi-day calendar selection with custom popover UI (#393)
* Add multi-day calendar selection with custom popover UI

Replace native DatePicker with a custom-themed CalendarPopover supporting
non-contiguous multi-day selection. Add --days CLI flag for comma-separated
date filtering that post-filters from the bounding range scan.

CLI: parseDaysFlag() parses and validates dates, filterProjectsByDays()
filters turns to only selected days. Verified that sum of individual --day
calls matches --days output across cost, calls, activities, models, and
providers.

Swift: DataClient passes --days for multi-day, with single-day fallback.
AppStore tracks selectedDays as Set<String> with PayloadCacheKey support.
CalendarPopover uses pending state committed only on Done tap.

* Clear + Done in calendar resets to current period

When user clears all selected days and taps Done, switch back to the
active period instead of silently keeping the old day selection.
2026-05-24 09:49:59 -07:00
iamtoruk
aa69857e30 Add configurable menubar status period (#302)
Some checks are pending
CI / semgrep (push) Waiting to run
The menubar status item can now track Today, Week, Month, or 6 Months
independently from the popover's active period. Setting is persisted
in UserDefaults and changeable from Settings or via `defaults write`.

Thanks @ozymandiashh. Closes #291.
2026-05-24 03:15:39 -07:00
森曜
da641eeb52
Pause menubar refresh after repeated stalls (#388) 2026-05-24 01:04:52 -07:00
Resham Joshi
33b1abbbef
Add tooling breakdowns to CLI and menubar (#373)
Some checks are pending
CI / semgrep (push) Waiting to run
* Fix Antigravity provider detection, Codex fork double-counting, and tab ordering

Antigravity:
- Handle ephemeral port (--https_server_port 0) via lsof fallback
- Force reparse when cached turns are 0 (server may have been unavailable)
- Persist precomputed costUSD in session cache for correct pricing
- Map gemini-pro-agent to gemini-3.1-pro pricing
- Add display names for gemini-pro-agent and gemini-3.5-flash-low

Codex:
- Detect forked sessions via forked_from_id in session_meta
- Skip replayed parent events within 5s of fork creation time
- Use parent session ID in dedup key so parent+fork don't double-count

Menubar:
- Sort provider tabs by cost descending instead of enum declaration order

* Add tooling breakdowns to CLI dashboard and menubar

Surface skills, subagents, tools, and MCP server usage in both the
text dashboard and menubar app. Parse subagent types from Agent/Task
tool calls, aggregate with skills into a merged "Skills & Agents"
panel. Remove Top Sessions panel from CLI dashboard.
2026-05-21 14:38:14 -07:00
Resham Joshi
a51d819a47
Fix Antigravity provider detection, Codex fork double-counting, and tab ordering (#372)
Antigravity:
- Handle ephemeral port (--https_server_port 0) via lsof fallback
- Force reparse when cached turns are 0 (server may have been unavailable)
- Persist precomputed costUSD in session cache for correct pricing
- Map gemini-pro-agent to gemini-3.1-pro pricing
- Add display names for gemini-pro-agent and gemini-3.5-flash-low

Codex:
- Detect forked sessions via forked_from_id in session_meta
- Skip replayed parent events within 5s of fork creation time
- Use parent session ID in dedup key so parent+fork don't double-count

Menubar:
- Sort provider tabs by cost descending instead of enum declaration order
2026-05-21 14:37:53 -07:00
Resham Joshi
0f55a446da
Fix per-provider data loss, history regression, and decode fragility (#362)
* Fix per-provider data loss, division-by-zero, and decode fragility

- Per-provider multi-day queries only merged cost/calls from cache,
  dropping categories/models/sessions/tokens. Remove broken cache
  shortcut and always do full parse for per-provider periods.
- Remove per-provider daily history double-counting from overlapping
  cache + live data.
- Guard maxCost against zero in ActivitySection and ModelsSection to
  prevent NaN in bar width calculations.
- Use offset-based ForEach ID in BarTooltipCard to avoid duplicate
  model name collisions.
- Make cacheHitPercent, topActivities, topModels, providers use
  decodeIfPresent for backward compat with older CLI versions.
- Skip currency switch when FX rate fetch fails with no cache,
  preventing rate/symbol desync.
- Use readSessionFile in Gemini parser for 128MB size cap.
- Truncate Codex userMessage to 500 chars like other providers.

* Restore cache-backed trend history for provider-filtered views

The previous commit removed the broken per-provider cache shortcut but
also dropped cache-backed daily history, causing provider-filtered views
to lose trend data outside the selected period range.

Use allCacheDays for historical days (cost/calls per provider is accurate
in cache) and today's entry from the full parse. No overlap since cache
ends at yesterday.
2026-05-20 04:16:48 -07:00
Resham Joshi
06f69484f3
Fix one-shot rate detection for all non-Claude providers (#355)
Some checks are pending
CI / semgrep (push) Waiting to run
* Add CodeBurn Pro Mac App Store app

SwiftUI MenuBarExtra with litellm-snapshot pricing, Claude/Codex/Copilot
parsers, session discovery, auto-refresh timer, and dashboard UI matching
the real menubar design.

* Add appstore/ to .gitignore

Private Mac App Store build, not for the public repo.

* Fix one-shot rate detection for Gemini, Vibe, Kiro, and Goose

Gemini and Mistral Vibe now emit per-assistant-message calls grouped
by user turn via turnId, so the classifier sees Edit->Bash->Edit as
retries instead of independent one-shot turns. Kiro and Goose record
per-message tool ordering via toolSequence for the same effect on
aggregated sessions.

Vibe now prefers meta.json.stats.session_cost over price-derived
estimates. Session cache bumped to v2. Insight pill switcher scrolls
horizontally instead of wrapping.

Closes #351.

* Remove dead geminiOrdinal variable and add toolSequence cache validation

* Restore geminiOrdinal for idx fallback dedup key
2026-05-18 15:56:14 -07:00
Resham Joshi
7cea9efb31
Add Optimize tab, token display modes, daily budget alerts, and project drill-down (#349)
* Add CodeBurn Pro Mac App Store app

SwiftUI MenuBarExtra with litellm-snapshot pricing, Claude/Codex/Copilot
parsers, session discovery, auto-refresh timer, and dashboard UI matching
the real menubar design.

* Add appstore/ to .gitignore

Private Mac App Store build, not for the public repo.

* Add Optimize tab, token display modes, daily budget alerts, and project drill-down

- New Optimize insight tab with Retry Tax and Routing Waste computations
  (pure math from session data, no LLM required)
- Retry tax: shows money wasted on failed edit retries, per-model breakdown
- Routing waste: counterfactual savings vs cheapest reliable model, per-model
- Token display modes: Cost ($), Tokens (up/down split), Total Tokens
- Daily budget alert: configurable threshold, flame turns yellow when exceeded
- Project drill-down: click project rows to see per-session cost, tokens, models
- Period-aware top sessions: 30-day view now shows 30-day costliest sessions
- Friendly project names: show directory name instead of full path, Home for ~
- Session cache TTL bumped to 180s to prevent re-parsing on non-today periods
- Audit fixes: array mutation, percentage rounding, ForEach ID collision,
  baseline minimum threshold, editTurns scoping, first-of-month edge case

* Fix model badge ForEach ID collision and budget warning provider filter

- SessionDetailsList model badges used id: \.name which silently drops
  duplicate model entries. Switched to enumerated offset-based ID.
- Hero budget warning compared against provider-filtered payload instead
  of todayPayload (all providers). Now matches the menubar flame tint.
2026-05-18 14:51:15 -07:00
Resham Joshi
58ccf84f02
Fix menubar per-provider performance (24s → 2s) and session cache safety (#344)
Some checks are pending
CI / semgrep (push) Waiting to run
Per-provider menubar calls now use loadDailyCache() instead of hydrateCache(),
splitting history into cache-based and fallback paths. Fixes session cache wipe
when scanProjectDirs/parseProviderSources receive empty dirs. Strips _dirty flag
before session cache serialization to prevent unnecessary 132MB rewrites. Removes
dead keychain code from both credential stores.
2026-05-17 13:54:38 -07:00
iamtoruk
b0131f698c Store credential cache in file instead of keychain, use cache for per-provider menubar
Credential cache: switched from keychain to file-based storage under
Application Support. Ad-hoc signed builds invalidate keychain ACLs on
every rebuild, causing repeated macOS password prompts. Existing
keychain entries are migrated to file on first read, then deleted.

Per-provider menubar: the Codex/Claude/etc tabs previously re-parsed
all sessions from scratch (22s). Now parses only today with the
provider filter and uses the daily cache for historical days, matching
the fast path the All tab already uses.

Daily cache bumped to v7 to force a clean rebuild after pricing and
provider changes since v6.
2026-05-17 07:18:58 -07:00
iamtoruk
9ad137f2b8 Fix dormant activation to bootstrap instead of refresh
When the user clicks Load Quota from dormant state after a clean
reinstall, the cached keychain item may not exist. Using the refresh
path triggered a macOS keychain prompt because it assumed the cache
was present. Now calls bootstrapSubscription/bootstrapCodex which
properly re-reads credentials from source.
2026-05-17 05:27:49 -07:00
iamtoruk
bf0c7cc993 Defer keychain access until user explicitly connects on plan tab
Adds a `dormant` state to SubscriptionLoadState so the menubar never
prompts for keychain permission on launch. Users must navigate to the
plan tab and click "Load Quota" / "Connect" to trigger credential access.

Also fixes a flaky TZ-boundary test (cli-status-menubar) by widening the
time offset to avoid generating timestamps in the future at UTC hour 0.
2026-05-17 00:31:33 -07:00
iamtoruk
e3a0593ed8 Fix menubar PATH discovery for nvm/volta/asdf/npm-global installs
GUI-launched apps inherit a minimal PATH that misses user-managed Node
directories. Scan ~/.volta/bin, ~/.npm-global/bin, ~/.asdf/shims, and
the newest nvm Node version at launch. All candidates pass isSafe()
validation. Closes #331.
2026-05-16 08:54:45 -07:00
iamtoruk
5696a74571 Merge main into feat/kimi-code-provider to resolve conflicts 2026-05-16 07:25:12 -07:00
iamtoruk
59a4d95b18 Merge main into feat/cline-provider to resolve conflicts 2026-05-16 05:58:10 -07:00
Resham Joshi
95884c01f3
Merge pull request #334 from vaibhavarora14/fix/provider-strip-scroll
fix(menubar): make provider strip reachable and mouse-wheel scrollable
2026-05-16 05:02:59 -07:00
Vaibhav Arora
8f35dcd128 fix(menubar): make provider strip reachable and mouse-wheel scrollable
Two related bugs in the macOS menubar `AgentTabStrip`:

1. With more detected providers than fit at the default 360pt popover
   width (~7+), the off-screen provider chips were unreachable. SwiftUI's
   horizontal `ScrollView` does not scroll from click-drag, and there
   was no other affordance to reveal the hidden tabs.

2. Independent mouse wheels could not scroll the horizontal strip.
   Standard wheels emit only vertical `deltaY` with
   `hasPreciseScrollingDeltas == false`, and a horizontal SwiftUI
   `ScrollView` ignores vertical-only deltas. Trackpads (which emit
   horizontal deltas natively) already worked.

Fix:

- Wrap the strip in `ScrollViewReader` and add overflow-aware
  left/right chevron buttons that programmatically scroll to the
  next/previous visible provider via `proxy.scrollTo(_, anchor: .center)`.
  Buttons only appear when `stripContentWidth > stripViewportWidth - 30`
  and disable at the ends.
- Install an `NSEvent.addLocalMonitorForEvents(matching: .scrollWheel)`
  in `.onAppear` (removed in `.onDisappear`). When the cursor is over
  the strip and the event is non-precise (`!hasPreciseScrollingDeltas`)
  with `deltaX≈0` and `deltaY≠0`, copy the `CGEvent` and transpose
  `scrollWheelEventDeltaAxis1` / `PointDeltaAxis1` / `FixedPtDeltaAxis1`
  onto axis 2 so the underlying NSScrollView receives a real horizontal
  delta.
- Track strip hover via a `@MainActor` singleton
  `AgentTabStripScrollState` so the local-monitor closure can read the
  latest hover status without capturing stale SwiftUI state.

Trackpad events are passed through untouched, so vertical scrolling
elsewhere in the popover is unaffected.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 19:52:57 +05:30
iamtoruk
909efcf989 Harden menubar refresh and installer 2026-05-14 18:32:15 -07:00
iamtoruk
478131d5b7 Harden menubar status refresh timer 2026-05-14 17:57:36 -07:00
iamtoruk
00c55873a4 Fix menubar tab refresh recovery 2026-05-14 11:26:15 -07:00
iamtoruk
403efd4727 Merge remote-tracking branch 'origin/main' into fix/menubar-version-prefix
# Conflicts:
#	package.json
#	src/parser.ts
2026-05-13 20:32:22 -07:00
iamtoruk
c626fc4a45 Fix menubar stale cache recovery 2026-05-13 20:22:15 -07:00
AgentSeal
03e22ecb80
Add IBM Bob provider with workspace extraction (#316)
Some checks are pending
CI / semgrep (push) Waiting to run
* Add IBM Bob provider

* Add workspace extraction for Cline-family providers

Extract project name from workspace directory in api_conversation_history.json
so sessions show actual folder names instead of the provider display name.
Thread projectPath through ParsedProviderCall to avoid unsanitizePath mangling
hyphenated folder names.

---------

Co-authored-by: ozymandiashh <234437643+ozymandiashh@users.noreply.github.com>
Co-authored-by: iamtoruk <hello@agentseal.org>
2026-05-11 20:54:13 -07:00
iamtoruk
b4b28becc8 Harden menubar refresh recovery 2026-05-11 20:44:06 -07:00
ozymandiashh
9187bc590a Add Cline provider 2026-05-12 00:31:41 +03:00
iamtoruk
f058f36dbd Normalize menubar version display 2026-05-11 11:21:39 -07:00
iamtoruk
33649e0a65 Refresh live quota progress from menubar 2026-05-11 11:09:20 -07:00
iamtoruk
ce0e1eb116 Make menubar refresh now reset stale state 2026-05-11 11:05:50 -07:00
iamtoruk
1149ab6e43 Fix menubar wake recovery and release asset selection 2026-05-11 10:57:02 -07:00
ozymandiashh
78cbfd3798 Add Kimi provider 2026-05-11 19:02:28 +03:00
Resham Joshi
180e14da82
Merge pull request #293 from getagentseal/fix/menubar-loading-watchdog
Some checks are pending
CI / semgrep (push) Waiting to run
Fix menubar loading recovery deadlocks
2026-05-10 10:32:56 -07:00
iamtoruk
d79deefaae Fix menubar refresh recovery deadlock 2026-05-10 03:30:56 -07:00
Resham Joshi
4c29f6b880
Add Crush provider plus per-provider icon column in README (#286)
Closes #278.

Adds Charmbracelet Crush as a lazy-loaded provider:
- src/providers/crush.ts: walks ~/.local/share/crush/projects.json
  (XDG_DATA_HOME and CRUSH_GLOBAL_DATA aware), opens each project's
  crush.db read-only, queries root sessions where parent_session_id
  IS NULL. Emits one ParsedProviderCall per session with real
  prompt_tokens, completion_tokens, cost (dollars), and the
  dominant model resolved from messages.model.
- src/providers/index.ts: register crush alongside cursor, goose,
  opencode, antigravity, cursor-agent in the lazy import path.
- tests/providers/crush.test.ts: 10 fixture-based tests covering
  discovery, parsing, missing-registry, malformed JSON, missing db,
  child session exclusion, dominant model selection, dedup, and
  array-shaped legacy registry.

Schema source: charmbracelet/crush@v0.66.1
internal/db/migrations/20250424200609_initial.sql, verified by
spawning a research agent against upstream. The schema *comments*
in that migration claim millisecond timestamps but every actual
INSERT/UPDATE uses strftime('%s', 'now') which returns Unix
seconds; the parser treats values as seconds. Tokscale's
parser (junhoyeo/tokscale#346) gets this wrong and is off by
1000x, plus its parser misses the prompt_tokens/completion_tokens
columns that exist in Crush's schema. Our integration uses both,
so Crush sessions get real per-model attribution.

Menubar:
- mac/Sources/CodeBurnMenubar/AppStore.swift: add .crush case to
  ProviderFilter and its cliArg switch.
- mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift: add
  Crush color to the per-tab color extension. The visibleFilters
  computed property already filters by detected providers, so the
  Crush tab appears automatically when a user has Crush data.

README:
- Replace the provider table with an icon-led layout. Icons live
  under assets/providers/<name>.<ext>. 14 icons sourced from
  junhoyeo/tokscale (MIT) under nominative fair use, 4 sourced
  separately: codex (OpenAI org avatar), cursor-agent (reuses the
  Cursor icon), kiro (kiro.dev favicon, ico->png via sips), omp
  (can1357/oh-my-pi icon.svg, MIT). Attribution line added.
- Add Crush row.

Docs:
- docs/providers/crush.md: full per-provider doc with verified
  schema excerpt, the seconds-vs-milliseconds quirk, and a
  "when fixing a bug here" checklist.
- docs/architecture.md: provider count 17 -> 18, test count
  41 -> 42, and crush in the lazy list.
- docs/providers/README.md: add Crush row to the lazy index.
- CONTRIBUTING.md: bump test count to 568 (was 558).

All 568 tests pass locally; swift build clean.
2026-05-09 20:47:56 -07:00
iamtoruk
66316aba38 Fix menubar stuck loading with non-blocking pipe I/O and watchdog
Replace blocking availableData drain with non-blocking POSIX read
that respects Task cancellation. Handle EINTR from child SIGCHLD,
close pipe fds after drain to prevent deadlock on oversized output,
and escalate SIGTERM to SIGKILL after 0.5s grace period.

Add 60-second loading watchdog as safety net that auto-clears stuck
state on each refresh loop tick.

Fixes #282
2026-05-09 14:27:48 -07:00
Resham Joshi
8208cf8ff5
Quiet routine pricing warnings + menubar recovery from stuck-loading (#266)
* Quiet routine pricing warnings + menubar recovery from stuck-loading

CLI:

- Default `codeburn` invocation no longer prints "no pricing data for model"
  warnings on every run. Greeting a fresh user with three lines of stderr
  before the dashboard even draws looked like the tool was broken on first
  launch. The warning now requires --verbose, and the suppressed pricing
  miss still results in $0 cost (correct for unmapped models).
- Local-model heuristic skips the warning entirely for Ollama tags
  (`qwen3.6:35b-a3b-bf16`), GGUF/quantized fingerprints, and similar names
  that will never have public pricing. The "update codeburn" hint was
  actively misleading there.
- When the warning does fire (with --verbose), it points users at
  `codeburn model-alias <model> <known-model>` as the actual escape hatch
  alongside the package update suggestion.

Menubar:

- Replace perpetual "Loading…" spinner with a FetchErrorOverlay when the
  per-key fetch fails and the cache is empty. User sees the error and a
  Retry button instead of an infinite hang.
- Add diagnostic breadcrumbs (NSLog, invisible to normal users — Console.app
  / `log stream --process CodeBurnMenubar` only) for the four states that
  produce a stuck loading overlay:
    - subprocess timeout after 45s
    - fetch result dropped due to Task cancellation (rapid tab switch)
    - fetch result dropped due to mid-fetch calendar rollover
    - retry attempt where the last successful fetch is >2 min stale
- Track lastSuccessByKey separately from cache freshness so the staleness
  diagnostic survives day-rollover cache wipes.

* Stop flashing the compare-view loading screen on background refresh

When the 30s CLI tick updated `projects` while the user was reading the
model comparison results, the projects-watching effect always fired
setLoadTrigger, which flipped phase to 'loading' and re-ran the slow
scanSelfCorrections walk over every provider's session directory. The
user lost their scroll position and saw a loading flash mid-read.

Recompute the comparison rows in place when:
- the user is already on the results phase, AND
- both picked models still exist in the new aggregate.

Skip the corrections rescan on these in-place refreshes — corrections
drift slowly enough that holding the previous value until the user
re-enters compare is acceptable, and the rescan is the slow part of the
load. Initial selection and post-selection load still run the full
pipeline.
2026-05-08 20:33:48 -07:00
iamtoruk
b317009181 Fix menubar stuck loading after sleep, double-click on pill tabs, oversized disconnected tabs
Sleep: track forceRefreshTask and cancel it on willSleep alongside
refreshLoopTask. Reset loadingCount on wake so orphaned fetches from
before sleep cannot leave the loading bar stuck.

Tabs: replace Button wrapper with onTapGesture on AgentTab so the
NSPopover hover tooltip does not eat the first click. Add
clickDismissed guard to prevent the popover from re-showing while
the mouse is still over the tab after a tap.

Tab size: only render the quota bar slot when quota data exists
(connected), not for every provider that supports quota. Disconnected
Claude/Codex tabs are now the same height as other tabs.
2026-05-08 13:00:35 -07:00