From 7a0b4e5d660e41eca600013f3fa3de5bdbeab28c Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Mon, 29 Jun 2026 02:05:26 +0300 Subject: [PATCH] fix(github): skip PR status resolution for a directory that no longer exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A deleted worktree often still has a session in the sidebar, which keeps polling its PR status — spending a git status call (the source of the noisy 'directory does not exist' errors) plus remote/repo resolution on a gone path. Bail out early when the directory is missing; the route already returns a benign no-repo result, which caches so it stops re-polling. --- packages/web/server/lib/github/pr-status.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/web/server/lib/github/pr-status.js b/packages/web/server/lib/github/pr-status.js index b8341360..89de3dd1 100644 --- a/packages/web/server/lib/github/pr-status.js +++ b/packages/web/server/lib/github/pr-status.js @@ -1,7 +1,18 @@ +import { stat } from 'node:fs/promises'; import { getRemotes, getStatus } from '../git/index.js'; import { resolveGitHubRepoFromDirectory } from './repo/index.js'; import { noteIfGitHubRateLimit } from './rate-limit.js'; +const directoryExists = async (dir) => { + if (!dir) return false; + try { + await stat(dir); + return true; + } catch { + return false; + } +}; + const REPO_DEFAULT_BRANCH_TTL_MS = 5 * 60_000; const defaultBranchCache = new Map(); const repoMetadataCache = new Map(); @@ -453,6 +464,14 @@ const findFirstMatchingPr = async ({ octokit, target, branch, sourceCandidates } }; export async function resolveGitHubPrStatus({ octokit, directory, branch, remoteName }) { + // A deleted worktree can still have a session in the sidebar that keeps + // requesting its PR status. Bail before touching git or GitHub for a + // directory that no longer exists — otherwise every poll spends a git call + // (and the remote/repo resolution that follows) on a path that's gone. + if (!(await directoryExists(directory))) { + return { repo: null, pr: null, defaultBranch: null, resolvedRemoteName: null }; + } + const normalizedBranch = normalizeText(branch); const normalizedRemoteName = normalizeText(remoteName) || 'origin';