@@ -115,14 +115,15 @@ type App struct {
115115 turnClient * turn.Client
116116 currentUser * github.User
117117 previousBlockedPRs map [string ]bool
118- notificationHistory map [string ]NotificationState // Track state and notification time per PR
118+ notificationHistory map [string ]NotificationState
119119 client * github.Client
120120 lastMenuState * MenuState
121121 targetUser string
122122 cacheDir string
123- incoming [] PR
123+ authError string
124124 outgoing []PR
125125 pendingTurnResults []TurnResult
126+ incoming []PR
126127 consecutiveFailures int
127128 updateInterval time.Duration
128129 mu sync.RWMutex
@@ -131,8 +132,54 @@ type App struct {
131132 noCache bool
132133 hideStaleIncoming bool
133134 loadingTurnData bool
134- enableReminders bool // Whether to send daily reminder notifications
135- enableAudioCues bool // Whether to play audio cues for notifications
135+ enableReminders bool
136+ enableAudioCues bool
137+ }
138+
139+ func loadCurrentUser (ctx context.Context , app * App ) {
140+ log .Println ("Loading current user..." )
141+
142+ if app .client == nil {
143+ log .Println ("Skipping user load - no GitHub client available" )
144+ return
145+ }
146+
147+ var user * github.User
148+ err := retry .Do (func () error {
149+ var retryErr error
150+ user , _ , retryErr = app .client .Users .Get (ctx , "" )
151+ if retryErr != nil {
152+ log .Printf ("GitHub Users.Get failed (will retry): %v" , retryErr )
153+ return retryErr
154+ }
155+ return nil
156+ },
157+ retry .Attempts (maxRetries ),
158+ retry .DelayType (retry .BackOffDelay ),
159+ retry .MaxDelay (maxRetryDelay ),
160+ retry .OnRetry (func (n uint , err error ) {
161+ log .Printf ("GitHub Users.Get retry %d/%d: %v" , n + 1 , maxRetries , err )
162+ }),
163+ retry .Context (ctx ),
164+ )
165+ if err != nil {
166+ log .Printf ("Warning: Failed to load current user after %d retries: %v" , maxRetries , err )
167+ if app .authError == "" {
168+ app .authError = fmt .Sprintf ("Failed to load user: %v" , err )
169+ }
170+ return
171+ }
172+
173+ if user == nil {
174+ log .Print ("Warning: GitHub API returned nil user" )
175+ return
176+ }
177+
178+ app .currentUser = user
179+ // Log if we're using a different target user (sanitized)
180+ if app .targetUser != "" && app .targetUser != user .GetLogin () {
181+ log .Printf ("Querying PRs for user '%s' instead of authenticated user" , sanitizeForLog (app .targetUser ))
182+ }
136183}
137184
138185func main () {
@@ -193,40 +240,13 @@ func main() {
193240 log .Println ("Initializing GitHub clients..." )
194241 err = app .initClients (ctx )
195242 if err != nil {
196- log .Fatalf ("Failed to initialize clients: %v" , err )
197- }
198-
199- log .Println ("Loading current user..." )
200- var user * github.User
201- err = retry .Do (func () error {
202- var retryErr error
203- user , _ , retryErr = app .client .Users .Get (ctx , "" )
204- if retryErr != nil {
205- log .Printf ("GitHub Users.Get failed (will retry): %v" , retryErr )
206- return retryErr
207- }
208- return nil
209- },
210- retry .Attempts (maxRetries ),
211- retry .DelayType (retry .BackOffDelay ),
212- retry .MaxDelay (maxRetryDelay ),
213- retry .OnRetry (func (n uint , err error ) {
214- log .Printf ("GitHub Users.Get retry %d/%d: %v" , n + 1 , maxRetries , err )
215- }),
216- retry .Context (ctx ),
217- )
218- if err != nil {
219- log .Fatalf ("Failed to load current user after %d retries: %v" , maxRetries , err )
220- }
221- if user == nil {
222- log .Fatal ("GitHub API returned nil user" )
243+ log .Printf ("Warning: Failed to initialize clients: %v" , err )
244+ app .authError = err .Error ()
245+ // Continue running with auth error - will show error in UI
223246 }
224- app .currentUser = user
225247
226- // Log if we're using a different target user (sanitized)
227- if app .targetUser != "" && app .targetUser != user .GetLogin () {
228- log .Printf ("Querying PRs for user '%s' instead of authenticated user" , sanitizeForLog (app .targetUser ))
229- }
248+ // Load current user if we have a client
249+ loadCurrentUser (ctx , app )
230250
231251 log .Println ("Starting systray..." )
232252 // Create a cancellable context for the application
@@ -242,16 +262,8 @@ func main() {
242262
243263func (app * App ) onReady (ctx context.Context ) {
244264 log .Println ("System tray ready" )
245- systray .SetTitle ("Loading PRs..." )
246265
247- // Set tooltip based on whether we're using a custom user
248- tooltip := "GitHub PR Monitor"
249- if app .targetUser != "" {
250- tooltip = fmt .Sprintf ("GitHub PR Monitor - @%s" , app .targetUser )
251- }
252- systray .SetTooltip (tooltip )
253-
254- // Set up click handlers
266+ // Set up click handlers first (needed for both success and error states)
255267 systray .SetOnClick (func (menu systray.IMenu ) {
256268 log .Println ("Icon clicked" )
257269 if menu != nil {
@@ -270,6 +282,26 @@ func (app *App) onReady(ctx context.Context) {
270282 }
271283 })
272284
285+ // Check if we have an auth error
286+ if app .authError != "" {
287+ systray .SetTitle ("⚠️" )
288+ systray .SetTooltip ("GitHub PR Monitor - Authentication Error" )
289+ // Create initial error menu
290+ app .rebuildMenu (ctx )
291+ // Clean old cache on startup
292+ app .cleanupOldCache ()
293+ return
294+ }
295+
296+ systray .SetTitle ("Loading PRs..." )
297+
298+ // Set tooltip based on whether we're using a custom user
299+ tooltip := "GitHub PR Monitor"
300+ if app .targetUser != "" {
301+ tooltip = fmt .Sprintf ("GitHub PR Monitor - @%s" , app .targetUser )
302+ }
303+ systray .SetTooltip (tooltip )
304+
273305 // Clean old cache on startup
274306 app .cleanupOldCache ()
275307
0 commit comments