Commit d64b1cc
fix(panel): honor explicit Quit; align side text with gauge center (#106)
* fix(panel): honor explicit Quit; align side text with gauge center
Two unrelated fixes bundled together:
1. KeepAlive: true caused launchd to respawn the panel after a user
clicks Quit. Switch new installs (install.sh + Bootstrap.writePlist)
to the dict form `KeepAlive: { SuccessfulExit: false }` so the
process restarts on crashes but respects clean exits. Existing
installs get a one-shot migration in cleanupPostUpdateBackup that
rewrites the plist on launch and reloads launchd, so the fix takes
effect without a reinstall.
2. CompactView's sideText (resting countdown / hover legend) sat above
the gauge digit's y-center because its intrinsic height differed
from the gauge cluster's. Pin sideText to the gauge cluster's full
height (size + 2 to match the halo Circle) so the ZStack's center
alignment lines up with QuotaGauge's centerReadout in both
compact-content modes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(panel): honor 429 Retry-After on the Claude usage probe
Hammering /api/oauth/usage with the same source IP kept stoking the
rate limit — once a 429 streak started it never cleared because every
60s poll kept the window alive. Track retryAfterUntil; while it's in
the future, short-circuit fetch() before hitting the network. Parse
the Retry-After header (delta-seconds or HTTP-date), fall back to 15
minutes when absent, clamp at 1 hour so a bogus value can't strand the
probe. Cleared on the next 200.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(panel): keep quit quit — don't relaunch via notify.sh
User Quit now drops a marker at ~/.stack-nudge/user-quit; notify.sh's
ensure_app_running gate honors it and stops opening the bundle on hook
events. The marker is cleared on the next manual launch, so reopening
restores normal auto-relaunch behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(widget): align usage side text with gauge + match hover legend weight
Drop the explicit Spacer in the usage pill so sideText fills the slack
(maxWidth: .infinity, leading) — gauge center and text center now share
the same y, and the expand button sits closer to the cluster instead of
being pushed to the far edge. Widen the pill from 150→170 to give the
two-line hover legend room without compressing the layout, and bump the
resting countdown to .medium/.secondary so it matches the hover legend's
visual weight (sizes were already equal at 9pt — the perceived gap was
weight + color tier).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(widget): simplify mini + full pill — symmetric margins, hover stability, cycling-only headline
Mini pill (usage mode):
- Reserve hoverLegend's measured width via PreferenceKey so the
countdown sits in a fixed-width slot — hovering no longer bumps the
expand button.
- Vertically center the visible text in sideText (countdown / hover
legend / "—" placeholder when no quota).
- Gate hover on nav.quota != nil so we don't flash placeholder legend
text on hover.
- Shrink pill 170→145 and bump horizontal padding 4→10 so both edge
gaps resolve to the same value.
Full pill (non-usage mode):
- Drop the middle Spacer + trailing minLength-4 Spacer in favor of a
single trailing Spacer; sessionBadge + expandButton now sit right
next to the headline.
- Shrink pill 320→290 so the right margin matches the left 12pt
padding.
- Strip the busy / recent-event / most-recent-active branches in the
headline — always show cycling active session names (falls back to
"watching" when no sessions are active). Drops the · token-count and
· position indicators from the cycling view.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(panel): address PR #106 review feedback
- writePlist: parameterize KeepAlive so the voice daemon keeps its
"always" restart policy. Wizard-installed daemons were inheriting the
panel's SuccessfulExit:false form, diverging from install.sh.
- QuotaProbe: distinguish "rate-limited" from "endpoint may have changed"
in the Usage tab so the message is accurate during a 429 backoff.
isRateLimited reads off retryAfterUntil; lastProbeFailed now only flags
real failures (non-200, non-429).
- parseRetryAfter: refactor to take String? so it can be unit-tested
without an HTTPURLResponse; add tests covering delta-seconds, HTTP-date,
negative values, >1h clamp, empty, and garbage input.
- gaugeClusterBody: extract `haloSize = size + 2` so the halo blur frame
and gauge frame share one source of truth; drop redundant explicit
HStack(alignment: .center).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>1 parent ead6c90 commit d64b1cc
8 files changed
Lines changed: 250 additions & 105 deletions
File tree
- Tests/StackNudgePanelCoreTests
- panel
Lines changed: 63 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
206 | | - | |
| 206 | + | |
207 | 207 | | |
208 | 208 | | |
209 | | - | |
| 209 | + | |
210 | 210 | | |
211 | 211 | | |
212 | 212 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
312 | 312 | | |
313 | 313 | | |
314 | 314 | | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
315 | 318 | | |
316 | 319 | | |
317 | 320 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
81 | 82 | | |
82 | 83 | | |
83 | 84 | | |
| |||
140 | 141 | | |
141 | 142 | | |
142 | 143 | | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
143 | 156 | | |
144 | 157 | | |
145 | 158 | | |
| |||
157 | 170 | | |
158 | 171 | | |
159 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
160 | 194 | | |
161 | 195 | | |
162 | 196 | | |
| |||
639 | 673 | | |
640 | 674 | | |
641 | 675 | | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
642 | 679 | | |
643 | 680 | | |
644 | 681 | | |
| 682 | + | |
645 | 683 | | |
646 | 684 | | |
647 | 685 | | |
| |||
660 | 698 | | |
661 | 699 | | |
662 | 700 | | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
663 | 705 | | |
664 | 706 | | |
665 | 707 | | |
| 708 | + | |
666 | 709 | | |
667 | 710 | | |
668 | 711 | | |
669 | 712 | | |
670 | 713 | | |
671 | | - | |
| 714 | + | |
672 | 715 | | |
673 | 716 | | |
674 | 717 | | |
| |||
0 commit comments