mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 08:03:12 +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.
153 lines
6.0 KiB
TypeScript
153 lines
6.0 KiB
TypeScript
import type { Repo } from '../../shared/repo-types'
|
|
import type { Worktree } from '../../shared/worktree/types'
|
|
import type { Store } from '../persistence'
|
|
import {
|
|
getLocalProjectGitExecOptions,
|
|
getLocalProjectWorktreeGitOptions,
|
|
getWorktreeMirrorDistro
|
|
} from '../project-runtime-git-options'
|
|
import { getBaseRefDefault, resolveDefaultBaseRefWithLocalGit } from '../git/repo'
|
|
import { resolveLocalGitUsername } from '../git/git-username'
|
|
import { computeWorkspaceRoot, getWorktreePathSettings } from '../ipc/worktree-logic'
|
|
import { resolveWorktreeCreateBase } from '../worktree-create-base'
|
|
import type { RuntimeManagedWorktreeCreateArgs } from './runtime-managed-worktree-create-types'
|
|
import type { RemoteFetchResult, RemoteTrackingBase } from './runtime-remote-fetch-controller'
|
|
import type { HostedReviewExecutionOptions } from '../source-control/hosted-review-git-options'
|
|
import { hasLocalGitOptions } from './runtime-worktree-selection'
|
|
import { hasLocalWorktreeBaseRef } from '../git/worktree-base-ref-probe'
|
|
import { resolveRuntimeLocalWorktreeCreateCandidate } from './runtime-local-worktree-create-candidate'
|
|
import { createRuntimeLocalGitWorktree } from './runtime-local-git-worktree-create'
|
|
import { materializeRuntimeLocalWorktree } from './runtime-local-worktree-materialization'
|
|
|
|
type LocalGitOptions = { wslDistro?: string }
|
|
type LocalGitArgs = [] | [LocalGitOptions]
|
|
|
|
export async function createRuntimeLocalManagedWorktree<T>(args: {
|
|
request: RuntimeManagedWorktreeCreateArgs
|
|
repo: Repo
|
|
store: Store
|
|
createdWithAgent: RuntimeManagedWorktreeCreateArgs['createdWithAgent']
|
|
hostedReviewExecutionContext?: HostedReviewExecutionOptions
|
|
resolveRemoteTrackingBase: (
|
|
path: string,
|
|
base: string,
|
|
...options: LocalGitArgs
|
|
) => Promise<RemoteTrackingBase | null>
|
|
hasRemoteTrackingRef: (
|
|
path: string,
|
|
base: RemoteTrackingBase,
|
|
...options: LocalGitArgs
|
|
) => Promise<boolean>
|
|
refreshRemoteTrackingBase: (
|
|
path: string,
|
|
base: RemoteTrackingBase,
|
|
...options: LocalGitArgs
|
|
) => Promise<RemoteFetchResult>
|
|
fetchRemote: (path: string, remote: string, ...options: LocalGitArgs) => Promise<void>
|
|
onWorktreeMetadataPersisted: (worktree: Worktree) => T
|
|
}) {
|
|
const { request, repo, store } = args
|
|
const settings = store.getSettings()
|
|
const pathSettings = getWorktreePathSettings(repo, settings, getWorktreeMirrorDistro(store, repo))
|
|
const gitExecOptions = getLocalProjectGitExecOptions(store, repo)
|
|
const worktreeGitOptions = getLocalProjectWorktreeGitOptions(store, repo)
|
|
const hasWorktreeGitOptions = hasLocalGitOptions(worktreeGitOptions)
|
|
const worktreeGitArgs: LocalGitArgs = hasWorktreeGitOptions ? [worktreeGitOptions] : []
|
|
// Username and base resolution are independent read-only probes. Starting
|
|
// both before awaiting removes one serial git/config round trip from create.
|
|
const usernamePromise =
|
|
!request.branchNameOverride && settings.branchPrefix === 'git-username'
|
|
? resolveLocalGitUsername(repo.path)
|
|
: Promise.resolve('')
|
|
const baseBranchPromise = resolveWorktreeCreateBase({
|
|
requestedBaseBranch: request.baseBranch,
|
|
repoWorktreeBaseRef: repo.worktreeBaseRef,
|
|
resolveDefaultBaseRef: () =>
|
|
hasWorktreeGitOptions
|
|
? resolveDefaultBaseRefWithLocalGit(gitExecOptions)
|
|
: getBaseRefDefault(repo.path),
|
|
isBaseUsable: async (candidate) => {
|
|
const remoteBase = await args.resolveRemoteTrackingBase(
|
|
repo.path,
|
|
candidate,
|
|
...worktreeGitArgs
|
|
)
|
|
if (
|
|
remoteBase &&
|
|
(await args.hasRemoteTrackingRef(repo.path, remoteBase, ...worktreeGitArgs))
|
|
) {
|
|
return true
|
|
}
|
|
return hasLocalWorktreeBaseRef(
|
|
repo.path,
|
|
candidate,
|
|
hasWorktreeGitOptions ? worktreeGitOptions : {}
|
|
)
|
|
}
|
|
})
|
|
const [username, baseBranch] = await Promise.all([usernamePromise, baseBranchPromise])
|
|
if (!baseBranch) {
|
|
throw new Error(
|
|
'Could not resolve a default base ref for this repo. Pass an explicit --base and try again.'
|
|
)
|
|
}
|
|
const candidate = await resolveRuntimeLocalWorktreeCreateCandidate({
|
|
request,
|
|
repo,
|
|
settings,
|
|
worktreePathSettings: pathSettings,
|
|
workspaceRoot: computeWorkspaceRoot(repo.path, pathSettings),
|
|
username,
|
|
store,
|
|
baseBranch,
|
|
localWorktreeGitOptions: worktreeGitOptions,
|
|
localWorktreeGitOptionArgs: worktreeGitArgs,
|
|
hostedReviewExecutionContext: args.hostedReviewExecutionContext
|
|
})
|
|
const git = await createRuntimeLocalGitWorktree({
|
|
request,
|
|
repo,
|
|
store,
|
|
settings,
|
|
baseBranch,
|
|
workspaceRoot: computeWorkspaceRoot(repo.path, pathSettings),
|
|
branchName: candidate.branchName,
|
|
worktreePath: candidate.worktreePath,
|
|
effectiveSanitizedName: candidate.effectiveSanitizedName,
|
|
checkoutExistingBranch: candidate.checkoutExistingBranch,
|
|
localWorktreeGitOptions: worktreeGitOptions,
|
|
hasLocalWorktreeGitOptions: hasWorktreeGitOptions,
|
|
localWorktreeGitOptionArgs: worktreeGitArgs,
|
|
resolveRemoteTrackingBase: args.resolveRemoteTrackingBase,
|
|
hasRemoteTrackingRef: args.hasRemoteTrackingRef,
|
|
refreshRemoteTrackingBase: args.refreshRemoteTrackingBase,
|
|
fetchRemote: args.fetchRemote
|
|
})
|
|
const materialized = await materializeRuntimeLocalWorktree({
|
|
request,
|
|
repo,
|
|
store,
|
|
settings,
|
|
created: git.created,
|
|
remoteTrackingBase: git.remoteTrackingBase,
|
|
sparseDirectories: git.sparseDirectories,
|
|
configuredPushTarget: git.configuredPushTarget,
|
|
checkoutExistingBranch: candidate.checkoutExistingBranch,
|
|
baseBranch,
|
|
branchName: candidate.branchName,
|
|
effectiveRequestedName: candidate.effectiveRequestedName,
|
|
requestedDisplayName: candidate.requestedDisplayName,
|
|
displayNameKind: candidate.displayNameKind,
|
|
effectiveSanitizedName: candidate.effectiveSanitizedName,
|
|
effectiveCreatedWithAgent: args.createdWithAgent,
|
|
localWorktreeGitOptions: worktreeGitOptions,
|
|
onMetadataPersisted: args.onWorktreeMetadataPersisted
|
|
})
|
|
return {
|
|
...materialized,
|
|
worktreePath: candidate.worktreePath,
|
|
created: git.created,
|
|
addResult: git.addResult
|
|
}
|
|
}
|