fix: stop repeated GitHub PR fetch warnings for non-GitHub repos

When opening a git repository without a GitHub remote, the server logs
were spammed with warnings every 5 seconds during worktree polling:

  WARN [Worktree] Failed to fetch GitHub PRs: Command failed: gh pr list
  ... no git remotes found

This happened because fetchGitHubPRs() ran `gh pr list` without first
checking if the project has a GitHub remote configured.

Changes:
- Add per-project cache for GitHub remote status with 5-minute TTL
- Check cache before attempting to fetch PRs, skip silently if no remote
- Add forceRefreshGitHub parameter to clear cache on manual refresh
- Pass forceRefreshGitHub when user clicks the refresh worktrees button

This allows users to add a GitHub remote and immediately detect it by
clicking the refresh button, while preventing log spam during normal
polling for projects without GitHub remotes.
This commit is contained in:
Stefan de Vogelaere
2026-01-17 12:32:42 +01:00
parent ef6b9ac2d2
commit 2d9e38ad99
5 changed files with 83 additions and 10 deletions

View File

@@ -39,7 +39,10 @@ export function useWorktrees({
logger.warn('Worktree API not available');
return;
}
const result = await api.worktree.listAll(projectPath, true);
// Pass forceRefreshGitHub when this is a manual refresh (not silent polling)
// This clears the GitHub remote cache so users can re-detect after adding a remote
const forceRefreshGitHub = !silent;
const result = await api.worktree.listAll(projectPath, true, forceRefreshGitHub);
if (result.success && result.worktrees) {
setWorktrees(result.worktrees);
setWorktreesInStore(projectPath, result.worktrees);

View File

@@ -1596,10 +1596,15 @@ function createMockWorktreeAPI(): WorktreeAPI {
return { success: true, worktrees: [] };
},
listAll: async (projectPath: string, includeDetails?: boolean) => {
listAll: async (
projectPath: string,
includeDetails?: boolean,
forceRefreshGitHub?: boolean
) => {
console.log('[Mock] Listing all worktrees:', {
projectPath,
includeDetails,
forceRefreshGitHub,
});
return {
success: true,

View File

@@ -1724,8 +1724,8 @@ export class HttpApiClient implements ElectronAPI {
getStatus: (projectPath: string, featureId: string) =>
this.post('/api/worktree/status', { projectPath, featureId }),
list: (projectPath: string) => this.post('/api/worktree/list', { projectPath }),
listAll: (projectPath: string, includeDetails?: boolean) =>
this.post('/api/worktree/list', { projectPath, includeDetails }),
listAll: (projectPath: string, includeDetails?: boolean, forceRefreshGitHub?: boolean) =>
this.post('/api/worktree/list', { projectPath, includeDetails, forceRefreshGitHub }),
create: (projectPath: string, branchName: string, baseBranch?: string) =>
this.post('/api/worktree/create', {
projectPath,

View File

@@ -705,7 +705,8 @@ export interface WorktreeAPI {
// List all worktrees with details (for worktree selector)
listAll: (
projectPath: string,
includeDetails?: boolean
includeDetails?: boolean,
forceRefreshGitHub?: boolean
) => Promise<{
success: boolean;
worktrees?: Array<{