fix(composer): honor pinned worktree base (#5542)

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo Hong 2026-06-16 16:51:48 -07:00 committed by GitHub
parent 21a01c7d6b
commit 3091b286ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 76 additions and 5 deletions

View File

@ -98,4 +98,13 @@ describe('useComposerState host-context boundaries', () => {
)
expect(submitLookup).toContain('sourceContext: selectedRepoGitHubSourceContext')
})
it('resolves quick-create base refs through the worktree-create precedence helper', () => {
const section = sourceBetween(HOOK_SOURCE, 'const submitBaseBranch', 'const createDisplayName')
expect(section).toContain('resolveWorktreeCreateBaseBranch')
expect(section).toContain('explicitBaseBranch: baseBranch')
expect(section).toContain('repoWorktreeBaseRef: selectedRepo.worktreeBaseRef')
expect(section).toContain('getRuntimeRepoBaseRefDefault')
})
})

View File

@ -26,6 +26,7 @@ import { tuiAgentToAgentKind } from '@/lib/telemetry'
import { isGitRepoKind } from '../../../shared/repo-kind'
import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
import { getRuntimeRepoBaseRefDefault } from '@/runtime/runtime-repo-client'
import { resolveWorktreeCreateBaseBranch } from '@/runtime/worktree-create-base'
import {
buildTaskSourceContextFromRepo,
type TaskSourceContext
@ -2655,11 +2656,15 @@ export function useComposerState(options: UseComposerStateOptions): UseComposerS
workspaceName,
preserveWorkspaceNameEdits: branchNameOverridePreservesNameEdits
})
const submitBaseBranch =
selectedRepoIsGit && !baseBranch
? ((await getRuntimeRepoBaseRefDefault(selectedRepoSettings, repoId).catch(() => null))
?.defaultBaseRef ?? undefined)
: baseBranch
const submitBaseBranch = selectedRepoIsGit
? await resolveWorktreeCreateBaseBranch({
explicitBaseBranch: baseBranch,
repoWorktreeBaseRef: selectedRepo.worktreeBaseRef,
loadDefaultBaseRef: async () =>
(await getRuntimeRepoBaseRefDefault(selectedRepoSettings, repoId).catch(() => null))
?.defaultBaseRef
})
: undefined
const createDisplayName =
smartGitHubResolution?.displayName ??
(nameIsAutoManaged ? submitTitleName?.displayName : undefined)

View File

@ -0,0 +1,42 @@
import { describe, expect, it, vi } from 'vitest'
import { resolveWorktreeCreateBaseBranch } from './worktree-create-base'
describe('resolveWorktreeCreateBaseBranch', () => {
it('uses an explicit Start-from selection before repo defaults', async () => {
const loadDefaultBaseRef = vi.fn().mockResolvedValue('origin/main')
await expect(
resolveWorktreeCreateBaseBranch({
explicitBaseBranch: 'origin/feature',
repoWorktreeBaseRef: 'dev',
loadDefaultBaseRef
})
).resolves.toBe('origin/feature')
expect(loadDefaultBaseRef).not.toHaveBeenCalled()
})
it('uses the pinned repo worktree base before resolving the git primary', async () => {
const loadDefaultBaseRef = vi.fn().mockResolvedValue('origin/main')
await expect(
resolveWorktreeCreateBaseBranch({
explicitBaseBranch: undefined,
repoWorktreeBaseRef: ' dev ',
loadDefaultBaseRef
})
).resolves.toBe('dev')
expect(loadDefaultBaseRef).not.toHaveBeenCalled()
})
it('falls back to the git primary when no explicit or pinned base exists', async () => {
await expect(
resolveWorktreeCreateBaseBranch({
explicitBaseBranch: undefined,
repoWorktreeBaseRef: undefined,
loadDefaultBaseRef: vi.fn().mockResolvedValue('origin/main')
})
).resolves.toBe('origin/main')
})
})

View File

@ -0,0 +1,15 @@
export async function resolveWorktreeCreateBaseBranch(args: {
explicitBaseBranch: string | undefined
repoWorktreeBaseRef: string | undefined
loadDefaultBaseRef: () => Promise<string | null | undefined>
}): Promise<string | undefined> {
if (args.explicitBaseBranch) {
return args.explicitBaseBranch
}
const pinnedBaseRef = args.repoWorktreeBaseRef?.trim()
if (pinnedBaseRef) {
return pinnedBaseRef
}
const defaultBaseRef = (await args.loadDefaultBaseRef())?.trim()
return defaultBaseRef || undefined
}