The app captured Gitea's OAuth refresh token on login but never used it --
an expired access token forced a full new browser-based login (and consent
screen) every time. Now silently exchanges the stored refresh token for a
new access token in the background, proactively before it goes stale,
shared via one AuthSession singleton across all five features' API clients
instead of each independently reading a possibly-stale token.
Verified Gitea's refresh_token grant shape against its own source
(routers/web/auth/oauth2_provider.go) before implementing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>