mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
fix(review): detect remote default branch asynchronously at startup (#609)
getDefaultBranch relied on `symbolic-ref refs/remotes/origin/HEAD` which is commonly unset in worktrees, manual remote setups, and long-lived repos. When absent, the code fell through to local `main`/`master`, silently losing the upstream-preference behavior. Adds `detectRemoteDefaultBranch()` — queries the remote via `git ls-remote --symref origin HEAD` to find the actual default branch name (works for any name: develop, trunk, etc.). The call is fire-and-forget at server startup: non-blocking, runs concurrently while the browser loads. By the time the user opens Branch diff or PR Diff (usually 1-2 seconds later), the result has arrived and `currentBase` has been silently upgraded to the upstream ref. If offline or slow, the 5-second timeout fires and the local fallback sticks. If the user has already switched bases manually, their choice is never overwritten. `ReviewGitRuntime.runGit` gains an optional `timeoutMs` param. Bun kills the process via setTimeout + proc.kill(). Pi uses spawnSync's native `timeout` option. Both treat timeout as a non-zero exit. For provenance purposes, this commit was AI assisted.
This commit is contained in:
@@ -11,10 +11,9 @@
|
||||
|
||||
import { isRemoteSession, getServerHostname, getServerPort } from "./remote";
|
||||
import type { Origin } from "@plannotator/shared/agents";
|
||||
import { type DiffType, type GitContext, runVcsDiff, getVcsFileContentsForDiff, canStageFiles, stageFile, unstageFile, resolveVcsCwd, validateFilePath, getVcsContext } from "./vcs";
|
||||
import { parseWorktreeDiffType } from "@plannotator/shared/review-core";
|
||||
import { type DiffType, type GitContext, runVcsDiff, getVcsFileContentsForDiff, canStageFiles, stageFile, unstageFile, resolveVcsCwd, validateFilePath, getVcsContext, gitRuntime } from "./vcs";
|
||||
import { parseWorktreeDiffType, detectRemoteDefaultBranch, resolveBaseBranch } from "@plannotator/shared/review-core";
|
||||
import type { AgentJobInfo } from "@plannotator/shared/agent-jobs";
|
||||
import { resolveBaseBranch } from "@plannotator/shared/review-core";
|
||||
import { getRepoInfo } from "./repo";
|
||||
import { handleImage, handleUpload, handleAgents, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete, handleFavicon, type OpencodeClient } from "./shared-handlers";
|
||||
import { contentHash, deleteDraft } from "./draft";
|
||||
@@ -144,6 +143,17 @@ export async function startReviewServer(
|
||||
// the reviewer is currently looking at. Honors an explicit initialBase from
|
||||
// the caller — e.g. programmatic Pi callers can request a non-detected base.
|
||||
let currentBase = options.initialBase || gitContext?.defaultBranch || "main";
|
||||
let baseEverSwitched = false;
|
||||
|
||||
// Fire-and-forget: query the remote for its actual default branch. If it
|
||||
// arrives before the user interacts, quietly upgrade currentBase from the
|
||||
// local fallback (e.g. "main") to the upstream ref (e.g. "origin/main").
|
||||
// Non-blocking — the server is already listening by the time this resolves.
|
||||
if (gitContext && !options.initialBase && !isPRMode) {
|
||||
detectRemoteDefaultBranch(gitRuntime, gitContext.cwd).then((remote) => {
|
||||
if (remote && !baseEverSwitched) currentBase = remote;
|
||||
});
|
||||
}
|
||||
|
||||
// Agent jobs — background process manager (late-binds serverUrl via getter)
|
||||
let serverUrl = "";
|
||||
@@ -496,6 +506,7 @@ export async function startReviewServer(
|
||||
currentGitRef = result.label;
|
||||
currentDiffType = newDiffType;
|
||||
currentBase = base;
|
||||
baseEverSwitched = true;
|
||||
currentError = result.error;
|
||||
|
||||
// Recompute gitContext for the effective cwd so the client's
|
||||
|
||||
Reference in New Issue
Block a user