fix(ui): route answer worktrees from source session

This commit is contained in:
Bohdan Triapitsyn
2026-09-04 19:46:21 +03:00
parent f160f3aac4
commit b4a38061bc
7 changed files with 234 additions and 61 deletions
@@ -15,9 +15,11 @@ let gitStatus: {
behind: number;
} | null = null;
let branchTracking: MockBranchTracking = {};
let isGitRepository = true;
const createdPayloads: CreateWorktreeArgs[] = [];
mock.module('@/lib/gitApi', () => ({
checkIsGitRepository: () => Promise.resolve(isGitRepository),
getGitStatus: () => (gitStatus ? Promise.resolve(gitStatus) : Promise.reject(new Error('no status'))),
getGitBranches: () => Promise.resolve({
all: [],
@@ -52,7 +54,11 @@ mock.module('@/lib/worktrees/worktreeManager', () => ({
},
}));
const { createWorktreeWithDefaults, withWorktreeRemoteStartRef } = await import('./worktreeCreate');
const {
createWorktreeWithDefaults,
withWorktreeRemoteStartRef,
WorktreeRequiresGitRepositoryError,
} = await import('./worktreeCreate');
const baseArgs = (overrides: CreateWorktreeArgs = {}): CreateWorktreeArgs => ({
preferredName: 'openchamber/feature',
@@ -168,9 +174,17 @@ describe('createWorktreeWithDefaults remote source integration', () => {
projectRoot = '/repo';
gitStatus = { current: 'main', tracking: 'origin/main', ahead: 0, behind: 0 };
branchTracking = { main: 'origin/main' };
isGitRepository = true;
createdPayloads.length = 0;
});
test('rejects a non-Git project before asking the runtime to create a worktree', async () => {
isGitRepository = false;
await expect(createWorktreeWithDefaults(project, baseArgs())).rejects.toThrow(WorktreeRequiresGitRepositoryError);
expect(createdPayloads).toHaveLength(0);
});
test('sets the new branch\'s own upstream when using the tracked remote source', async () => {
gitStatus = { current: 'main', tracking: 'origin/main', ahead: 0, behind: 15 };
@@ -1,8 +1,15 @@
import { getGitBranches, getGitStatus } from '@/lib/gitApi';
import { checkIsGitRepository, getGitBranches, getGitStatus } from '@/lib/gitApi';
import type { CreateWorktreeArgs, ProjectRef } from '@/lib/worktrees/worktreeManager';
import { createWorktree } from '@/lib/worktrees/worktreeManager';
import { getRootBranch, resolveProjectRoot } from '@/lib/worktrees/worktreeStatus';
export class WorktreeRequiresGitRepositoryError extends Error {
constructor() {
super('Worktree creation requires a Git repository');
this.name = 'WorktreeRequiresGitRepositoryError';
}
}
const parseTrackingRef = (tracking: string | null | undefined): { remote: string; branch: string } | null => {
const value = String(tracking || '').trim().replace(/^remotes\//, '');
if (!value) {
@@ -162,6 +169,10 @@ export const createWorktreeWithDefaults = async (
args: CreateWorktreeArgs,
options?: { resolvedRootTrackingRemote?: string | null }
) => {
const isGitRepository = await checkIsGitRepository(project.path);
if (!isGitRepository) {
throw new WorktreeRequiresGitRepositoryError();
}
const remoteArgs = await withWorktreeRemoteStartRef(project, args);
const resolvedArgs = await withWorktreeUpstreamDefaults(project.path, remoteArgs, options);
return createWorktree(project, resolvedArgs);