( worktreePath: string, )
| 22 | * Results are cached for 10 seconds. |
| 23 | */ |
| 24 | export async function fetchGitHubPRStatus( |
| 25 | worktreePath: string, |
| 26 | ): Promise<GitHubStatus | null> { |
| 27 | // Check cache first |
| 28 | const cached = cache.get(worktreePath); |
| 29 | if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) { |
| 30 | return cached.data; |
| 31 | } |
| 32 | |
| 33 | try { |
| 34 | // First, get the repo URL |
| 35 | const repoUrl = await getRepoUrl(worktreePath); |
| 36 | if (!repoUrl) { |
| 37 | return null; |
| 38 | } |
| 39 | |
| 40 | // Get current branch name |
| 41 | const { stdout: branchOutput } = await execFileAsync( |
| 42 | "git", |
| 43 | ["rev-parse", "--abbrev-ref", "HEAD"], |
| 44 | { cwd: worktreePath }, |
| 45 | ); |
| 46 | const branchName = branchOutput.trim(); |
| 47 | |
| 48 | // Check if branch exists on remote and get PR info in parallel |
| 49 | const [branchCheck, prInfo] = await Promise.all([ |
| 50 | branchExistsOnRemote(worktreePath, branchName), |
| 51 | getPRForBranch(worktreePath, branchName), |
| 52 | ]); |
| 53 | |
| 54 | // Convert result to boolean - only "exists" is true |
| 55 | // "not_found" and "error" both mean we can't confirm it exists |
| 56 | const existsOnRemote = branchCheck.status === "exists"; |
| 57 | |
| 58 | const result: GitHubStatus = { |
| 59 | pr: prInfo, |
| 60 | repoUrl, |
| 61 | branchExistsOnRemote: existsOnRemote, |
| 62 | lastRefreshed: Date.now(), |
| 63 | }; |
| 64 | |
| 65 | // Cache the result |
| 66 | cache.set(worktreePath, { data: result, timestamp: Date.now() }); |
| 67 | |
| 68 | return result; |
| 69 | } catch { |
| 70 | // Any error (gh not installed, not auth'd, etc.) - return null |
| 71 | return null; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | async function getRepoUrl(worktreePath: string): Promise<string | null> { |
| 76 | try { |
no test coverage detected