Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/main/agent-hooks/first-work-branch-rename.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
FIRST_WORK_BRANCH_RENAME_SETTLED_CACHE_LIMIT,
maybeAutoRenameBranchOnFirstWork,
resetFirstWorkBranchRenameState,
type AutoRenameBranchEligibility,
type FirstWorkBranchRenameDeps
} from './first-work-branch-rename'
import {
Expand Down Expand Up @@ -378,6 +379,22 @@ describe('maybeAutoRenameBranchOnFirstWork', () => {
expect(onRenamed).not.toHaveBeenCalled()
})

it('retries when Orca-created eligibility is not available on the first working event', async () => {
let eligibility: AutoRenameBranchEligibility = 'transient-unknown'
const { deps, onRenamed } = makeDeps({
getAutoRenameBranchEligibility: () => eligibility
})

await maybeAutoRenameBranchOnFirstWork(workingEvent(), deps)
expect(generateBranchNameMock).not.toHaveBeenCalled()

eligibility = 'eligible'
await maybeAutoRenameBranchOnFirstWork(workingEvent(), deps)

expect(generateBranchNameMock).toHaveBeenCalled()
expect(onRenamed).toHaveBeenCalledWith(REPO_ID)
})

it('suffixes the branch, display name, and folder together on collision', async () => {
gitExecFileAsyncMock.mockImplementation(
gitResponder({
Expand Down
16 changes: 15 additions & 1 deletion src/main/agent-hooks/first-work-branch-rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export type FirstWorkBranchRenameEvent = {
isReplay: boolean | undefined
}

export type AutoRenameBranchEligibility = 'eligible' | 'transient-unknown' | 'permanent-ineligible'

export type FirstWorkBranchRenameDeps = {
getSettings: () => GlobalSettings
getRepo: (repoId: string) => Repo | undefined
Expand All @@ -54,6 +56,11 @@ export type FirstWorkBranchRenameDeps = {
isPendingFirstAgentMessageRename?: (worktreeId: string) => boolean
/** True only for Orca-created worktrees whose branch Orca is allowed to rename. */
canRenameOrcaCreatedBranch: (worktreeId: string) => boolean
/**
* Classifies Orca-created branch metadata. Missing metadata can be transient
* during worktree creation, so it must not permanently settle auto-rename.
*/
getAutoRenameBranchEligibility?: (worktreeId: string) => AutoRenameBranchEligibility
/** Persist a new sidebar display name for the worktree. */
setDisplayName: (worktreeId: string, displayName: string) => void
/** Align the on-disk folder with the new branch leaf (best-effort, local-only). */
Expand Down Expand Up @@ -199,7 +206,14 @@ async function runAutoRename(
if (!currentBranch || currentBranch === 'HEAD') {
return retry(`no checked-out branch (${currentBranch || 'empty'})`)
}
if (!deps.canRenameOrcaCreatedBranch(worktreeId)) {

const eligibility =
deps.getAutoRenameBranchEligibility?.(worktreeId) ??
(deps.canRenameOrcaCreatedBranch(worktreeId) ? 'eligible' : 'permanent-ineligible')
if (eligibility === 'transient-unknown') {
return retry('worktree auto-rename eligibility is not available yet')
}
if (eligibility === 'permanent-ineligible') {
return stop(`worktree is not eligible for auto-rename`, true)
}
// Only rename a branch Orca auto-named — never one the user chose.
Expand Down
10 changes: 10 additions & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,16 @@ function maybeAutoRenameBranchOnFirstWorkFromHook(event: {
// Only worktrees Orca stamped at creation are safe to auto-rename.
return !!meta?.orcaCreationSource && meta.preserveBranchOnDelete !== true
},
getAutoRenameBranchEligibility: (worktreeId) => {
const meta = currentStore.getWorktreeMeta(worktreeId)
if (!meta) {
return 'transient-unknown'
}
if (!meta.orcaCreationSource || meta.preserveBranchOnDelete === true) {
return 'permanent-ineligible'
}
return 'eligible'
},
setDisplayName: (worktreeId, displayName) => {
const scope = parseWorkspaceKey(worktreeId)
if (scope?.type === 'folder') {
Expand Down
Loading