fix(worktree): gate sessions on bootstrap readiness (#1762)
Co-authored-by: Leonid Skorobogatyy <bash@opencode.itc.local> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Leonid Skorobogatyy
Bohdan Triapitsyn
parent
03e6f789a4
commit
8c1a24089d
@@ -6,7 +6,10 @@ const registeredDirectories: Array<{ sessionID: string; directory: string }> = [
|
||||
const ensureChildCalls: Array<{ directory: string; bootstrap?: boolean }> = [];
|
||||
const worktreeMetadataCalls: Array<{ sessionId: string; path: string }> = [];
|
||||
const worktreeCreateCalls: Array<{ project: { id?: string; path: string }; args: Record<string, unknown>; options: unknown }> = [];
|
||||
const worktreeBootstrapWaitCalls: string[] = [];
|
||||
const operationOrder: string[] = [];
|
||||
let isGitRepository = false;
|
||||
let waitForWorktreeSetup = false;
|
||||
const createWorktreeWithDefaultsMock = mock((project: { id?: string; path: string }, args: Record<string, unknown>, options: unknown) => {
|
||||
worktreeCreateCalls.push({ project, args, options });
|
||||
return Promise.resolve({
|
||||
@@ -52,12 +55,15 @@ mock.module('@/lib/opencode/client', () => ({
|
||||
currentDirectory = previous;
|
||||
}
|
||||
},
|
||||
createSession: async (params?: { title?: string }): Promise<Session> => ({
|
||||
id: 'ses_multirun',
|
||||
title: params?.title ?? '',
|
||||
directory: currentDirectory,
|
||||
time: { created: 1, updated: 1 },
|
||||
} as Session),
|
||||
createSession: async (params?: { title?: string }): Promise<Session> => {
|
||||
operationOrder.push(`createSession:${currentDirectory}`);
|
||||
return {
|
||||
id: 'ses_multirun',
|
||||
title: params?.title ?? '',
|
||||
directory: currentDirectory,
|
||||
time: { created: 1, updated: 1 },
|
||||
} as Session;
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -70,11 +76,20 @@ mock.module('@/lib/worktrees/worktreeCreate', () => ({
|
||||
resolveRootTrackingRemote: mock(() => Promise.resolve(null)),
|
||||
}));
|
||||
|
||||
mock.module('@/lib/worktrees/worktreeBootstrap', () => ({
|
||||
waitForWorktreeBootstrap: (directory: string) => {
|
||||
worktreeBootstrapWaitCalls.push(directory);
|
||||
operationOrder.push(`wait:${directory}`);
|
||||
return Promise.resolve();
|
||||
},
|
||||
}));
|
||||
|
||||
mock.module('@/lib/worktrees/worktreeStatus', () => ({
|
||||
getRootBranch: mock(() => Promise.resolve('main')),
|
||||
}));
|
||||
|
||||
mock.module('@/lib/openchamberConfig', () => ({
|
||||
getWorktreeSetupWaitEnabled: mock(() => Promise.resolve(waitForWorktreeSetup)),
|
||||
saveWorktreeSetupCommands: mock(() => Promise.resolve()),
|
||||
}));
|
||||
|
||||
@@ -139,7 +154,10 @@ describe('useMultiRunStore', () => {
|
||||
ensureChildCalls.length = 0;
|
||||
worktreeMetadataCalls.length = 0;
|
||||
worktreeCreateCalls.length = 0;
|
||||
worktreeBootstrapWaitCalls.length = 0;
|
||||
operationOrder.length = 0;
|
||||
isGitRepository = false;
|
||||
waitForWorktreeSetup = false;
|
||||
childState.session = [];
|
||||
childState.sessionTotal = 0;
|
||||
childState.limit = 5;
|
||||
@@ -181,7 +199,30 @@ describe('useMultiRunStore', () => {
|
||||
expect(worktreeCreateCalls[0]?.project).toEqual({ id: 'project-1', path: '/repo' });
|
||||
expect(worktreeCreateCalls[0]?.args.returnAfterDirectoryCreated).toBe(true);
|
||||
expect(worktreeCreateCalls[0]?.options).toEqual({ resolvedRootTrackingRemote: null });
|
||||
expect(worktreeBootstrapWaitCalls).toEqual([]);
|
||||
expect(operationOrder).toEqual(['createSession:/repo-worktrees/fix-thing']);
|
||||
expect(registeredDirectories).toEqual([{ sessionID: 'ses_multirun', directory: '/repo-worktrees/fix-thing' }]);
|
||||
expect(worktreeMetadataCalls).toEqual([{ sessionId: 'ses_multirun', path: '/repo-worktrees/fix-thing' }]);
|
||||
});
|
||||
|
||||
test('waits for isolated worktree bootstrap when setup wait is enabled', async () => {
|
||||
isGitRepository = true;
|
||||
waitForWorktreeSetup = true;
|
||||
|
||||
const result = await useMultiRunStore.getState().createMultiRun({
|
||||
name: 'Fix thing',
|
||||
isolateRuns: true,
|
||||
groups: [{
|
||||
prompt: 'Fix it',
|
||||
models: [{ providerID: 'anthropic', modelID: 'claude-sonnet-4-5' }],
|
||||
}],
|
||||
});
|
||||
|
||||
expect(result?.sessionIds).toEqual(['ses_multirun']);
|
||||
expect(worktreeBootstrapWaitCalls).toEqual(['/repo-worktrees/fix-thing']);
|
||||
expect(operationOrder).toEqual([
|
||||
'wait:/repo-worktrees/fix-thing',
|
||||
'createSession:/repo-worktrees/fix-thing',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,9 +4,10 @@ import { routeMessage, useSessionUIStore } from '@/sync/session-ui-store';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
import type { CreateMultiRunParams, CreateMultiRunResult } from '@/types/multirun';
|
||||
import { opencodeClient } from '@/lib/opencode/client';
|
||||
import { saveWorktreeSetupCommands } from '@/lib/openchamberConfig';
|
||||
import { getWorktreeSetupWaitEnabled, saveWorktreeSetupCommands } from '@/lib/openchamberConfig';
|
||||
import type { ProjectRef } from '@/lib/worktrees/worktreeManager';
|
||||
import { createWorktreeWithDefaults, resolveRootTrackingRemote } from '@/lib/worktrees/worktreeCreate';
|
||||
import { waitForWorktreeBootstrap } from '@/lib/worktrees/worktreeBootstrap';
|
||||
import { getRootBranch } from '@/lib/worktrees/worktreeStatus';
|
||||
import { checkIsGitRepository } from '@/lib/gitApi';
|
||||
import { useDirectoryStore } from './useDirectoryStore';
|
||||
@@ -244,6 +245,10 @@ export const useMultiRunStore = create<MultiRunStore>()(
|
||||
kind: 'standard' as const,
|
||||
};
|
||||
|
||||
if (await getWorktreeSetupWaitEnabled(project)) {
|
||||
await waitForWorktreeBootstrap(worktreeMetadata.path);
|
||||
}
|
||||
|
||||
const session = await opencodeClient.withDirectory(
|
||||
worktreeMetadata.path,
|
||||
() => opencodeClient.createSession({ title: sessionTitle }),
|
||||
|
||||
Reference in New Issue
Block a user