mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 00:03:15 +00:00
The speculative warm-up that runs while the create composer is open resolved
refs and fetched with host Git even when the project's runtime is a WSL distro,
while both the checkout preparation it feeds (`prepareWorktreeCreateForRepo`,
which already resolves `{ wslDistro }` itself) and the real create path run
inside the distro.
The concrete cost was a discarded fetch: `getCanonicalFetchKey` namespaces the
runtime's remote-fetch cache `wsl:<distro>` vs `local`, so the warm-up's fetch
landed in a namespace create never looks at, and create fetched again. On a
Windows host with no usable host-side Git the probes also failed outright, so
that cohort got no warm-up at all.
Thread the project's worktree Git options through the prefetch (resolved by a
non-throwing helper, because an optimistic warm-up must not surface a
repair-required runtime as a failure) so every probe and fetch runs where create
runs. `gitOptions` is a required argument, so a caller cannot drop the routing
silently. Host-routed calls keep their original arity, so macOS, Linux,
native-Windows-host projects, SSH repos and folder workspaces are unchanged.
Narrower than it looks: for a repo under \\wsl.localhost\<distro>\... the probes
were already routed by cwd, and for a repo on a Windows drive letter host Git
and WSL Git read the same on-disk repository, so the answers were already
correct there. What those cohorts gain is a fetch create can reuse; what they
pay is that the probes now run inside the distro (over /mnt/c for drive-letter
repos, which also newly arms the linked-worktree routing probe) and the
speculative fetch now shares create's per-remote fetch queue, as it always has
on native platforms.
Also collapse the three byte-equivalent copies of `hasLocalWorktreeBaseRef`
(create, prefetch, remote-repo create) into one in
git/worktree-base-ref-probe.ts, drop the host-only `hasLocalCommitObject` that
caused the routing bug, and add the first routing assertions on the create-path
consumers of the now-shared probe.
114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
import type { BranchPrefixStrategy } from '../../shared/ui-chrome-types'
|
|
import type { Repo } from '../../shared/repo-types'
|
|
import { getPRForBranch } from '../github/client'
|
|
import { gitExecFileAsync } from '../git/runner'
|
|
import { listWorktrees } from '../git/worktree'
|
|
import { computeValidatedBranchName } from '../ipc/worktree-logic'
|
|
import { getHostedReviewForBranch } from '../source-control/hosted-review'
|
|
import {
|
|
getSelectedReviewBranch,
|
|
getSelectedReviewLookupHints,
|
|
type SelectedReviewBranchInput
|
|
} from './selected-review-branch'
|
|
import { hasLocalGitOptions, normalizeLocalBranchName } from './runtime-worktree-selection'
|
|
import type { HostedReviewExecutionOptions } from '../source-control/hosted-review-git-options'
|
|
|
|
export async function resolveCreateBranchName(
|
|
repoPath: string,
|
|
branchNameOverride: string | undefined,
|
|
sanitizedName: string,
|
|
settings: { branchPrefix: string; branchPrefixCustom?: string },
|
|
username: string | null,
|
|
gitOptions: { wslDistro?: string } = {}
|
|
): Promise<string> {
|
|
if (!branchNameOverride) {
|
|
return computeValidatedBranchName(
|
|
sanitizedName,
|
|
{ ...settings, branchPrefix: settings.branchPrefix as BranchPrefixStrategy },
|
|
username
|
|
)
|
|
}
|
|
if (branchNameOverride.startsWith('-')) {
|
|
throw new Error('Branch name must not start with "-"')
|
|
}
|
|
await gitExecFileAsync(['check-ref-format', '--branch', branchNameOverride], {
|
|
cwd: repoPath,
|
|
...gitOptions
|
|
})
|
|
return branchNameOverride
|
|
}
|
|
|
|
export async function canCheckoutExistingLocalBranch(
|
|
repoPath: string,
|
|
branchName: string,
|
|
baseBranch: string,
|
|
gitOptions: { wslDistro?: string } = {}
|
|
): Promise<boolean> {
|
|
let localHead = ''
|
|
try {
|
|
const { stdout } = await gitExecFileAsync(
|
|
['rev-parse', '--verify', '--quiet', `refs/heads/${branchName}^{commit}`],
|
|
{ cwd: repoPath, ...gitOptions }
|
|
)
|
|
localHead = stdout.trim()
|
|
} catch {
|
|
return false
|
|
}
|
|
if (normalizeLocalBranchName(baseBranch) !== branchName) {
|
|
if (!localHead) {
|
|
return false
|
|
}
|
|
try {
|
|
const { stdout } = await gitExecFileAsync(
|
|
['rev-parse', '--verify', '--quiet', `${baseBranch}^{commit}`],
|
|
{ cwd: repoPath, ...gitOptions }
|
|
)
|
|
if (stdout.trim() !== localHead) {
|
|
return false
|
|
}
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
const worktrees = await listWorktrees(repoPath, gitOptions)
|
|
return !worktrees.some((worktree) => normalizeLocalBranchName(worktree.branch) === branchName)
|
|
}
|
|
|
|
export function getLocalGitHubPrForBranch(
|
|
repoPath: string,
|
|
branchName: string,
|
|
gitOptions: { wslDistro?: string }
|
|
): ReturnType<typeof getPRForBranch> {
|
|
return hasLocalGitOptions(gitOptions)
|
|
? getPRForBranch(repoPath, branchName, null, null, null, {
|
|
localGitExecOptions: gitOptions
|
|
})
|
|
: getPRForBranch(repoPath, branchName)
|
|
}
|
|
|
|
export async function getSelectedHostedReviewForBranch(
|
|
repo: Pick<Repo, 'path' | 'connectionId'>,
|
|
branchName: string,
|
|
args: SelectedReviewBranchInput,
|
|
executionOptions: HostedReviewExecutionOptions = {}
|
|
): Promise<{ matchesSelected: boolean; number: number } | null> {
|
|
const selectedReview = getSelectedReviewBranch(args)
|
|
if (!selectedReview) {
|
|
return null
|
|
}
|
|
const review = await getHostedReviewForBranch({
|
|
repoPath: repo.path,
|
|
connectionId: repo.connectionId ?? null,
|
|
branch: branchName,
|
|
...executionOptions,
|
|
...getSelectedReviewLookupHints(args)
|
|
})
|
|
return review
|
|
? {
|
|
matchesSelected:
|
|
review.provider === selectedReview.provider && review.number === selectedReview.number,
|
|
number: review.number
|
|
}
|
|
: null
|
|
}
|