From 78c851f7cd4b1fe6cc591331eaaa5fffb22431f5 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Sun, 7 Jun 2026 02:05:10 +0300 Subject: [PATCH] feat: open isolated multirun sessions before setup completes Open isolated Multi-Run sessions while worktree setup continues in the background Apply the faster flow to VS Code Agent Manager isolated runs Document the new Multi-Run and Agent Manager behavior --- CHANGELOG.md | 5 ++ .../ui/src/stores/useMultiRunStore.test.ts | 49 ++++++++++++++++++- packages/ui/src/stores/useMultiRunStore.ts | 1 + packages/vscode/CHANGELOG.md | 5 ++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c48b9613..ca34f232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +- Chat: added `/handoff-review` to open a linked review session for the current workspace changes, with actions to send review feedback and implementation replies between the sessions. +- Worktrees: creating a single new worktree session now opens the session immediately while worktree setup continues in the background. +- Multi-Run: creating isolated runs now opens sessions immediately while worktree setup continues in the background. +- Sessions: chat folder assignments now stay in place after reloads. + ## [1.12.3] - 2026-06-05 - Windows/Startup: WSL OpenCode installs are no longer detected or launched; install OpenCode natively on Windows and configure `opencode.cmd` or `opencode.exe` instead. diff --git a/packages/ui/src/stores/useMultiRunStore.test.ts b/packages/ui/src/stores/useMultiRunStore.test.ts index b3ef3f00..6af180c6 100644 --- a/packages/ui/src/stores/useMultiRunStore.test.ts +++ b/packages/ui/src/stores/useMultiRunStore.test.ts @@ -4,6 +4,24 @@ import type { Session } from '@opencode-ai/sdk/v2'; const upsertedSessions: Session[] = []; 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; options: unknown }> = []; +let isGitRepository = false; +const createWorktreeWithDefaultsMock = mock((project: { id?: string; path: string }, args: Record, options: unknown) => { + worktreeCreateCalls.push({ project, args, options }); + return Promise.resolve({ + source: 'sdk', + name: 'fix-thing', + path: '/repo-worktrees/fix-thing', + projectDirectory: '/repo', + branch: 'fix-thing', + label: 'fix-thing', + worktreeRoot: '/repo-worktrees/fix-thing', + worktreeStatus: 'pending', + headState: 'branch', + worktreeSource: 'created-for-session', + }); +}); const childState = { session: [] as Session[], sessionTotal: 0, @@ -16,6 +34,9 @@ mock.module('@/sync/session-ui-store', () => ({ useSessionUIStore: { getState: () => ({ markSessionAsOpenChamberCreated: mock(() => undefined), + setWorktreeMetadata: (sessionId: string, metadata: { path: string }) => { + worktreeMetadataCalls.push({ sessionId, path: metadata.path }); + }, }), }, })); @@ -41,11 +62,11 @@ mock.module('@/lib/opencode/client', () => ({ })); mock.module('@/lib/gitApi', () => ({ - checkIsGitRepository: mock(() => Promise.resolve(false)), + checkIsGitRepository: mock(() => Promise.resolve(isGitRepository)), })); mock.module('@/lib/worktrees/worktreeCreate', () => ({ - createWorktreeWithDefaults: mock(), + createWorktreeWithDefaults: createWorktreeWithDefaultsMock, resolveRootTrackingRemote: mock(() => Promise.resolve(null)), })); @@ -116,6 +137,9 @@ describe('useMultiRunStore', () => { upsertedSessions.length = 0; registeredDirectories.length = 0; ensureChildCalls.length = 0; + worktreeMetadataCalls.length = 0; + worktreeCreateCalls.length = 0; + isGitRepository = false; childState.session = []; childState.sessionTotal = 0; childState.limit = 5; @@ -139,4 +163,25 @@ describe('useMultiRunStore', () => { expect(ensureChildCalls).toEqual([{ directory: '/repo', bootstrap: false }]); expect(childState.session.map((session) => session.id)).toEqual(['ses_multirun']); }); + + test('uses fast background worktree creation for isolated runs', async () => { + isGitRepository = 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(worktreeCreateCalls.length).toBe(1); + 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(registeredDirectories).toEqual([{ sessionID: 'ses_multirun', directory: '/repo-worktrees/fix-thing' }]); + expect(worktreeMetadataCalls).toEqual([{ sessionId: 'ses_multirun', path: '/repo-worktrees/fix-thing' }]); + }); }); diff --git a/packages/ui/src/stores/useMultiRunStore.ts b/packages/ui/src/stores/useMultiRunStore.ts index a5b856d0..310e29b9 100644 --- a/packages/ui/src/stores/useMultiRunStore.ts +++ b/packages/ui/src/stores/useMultiRunStore.ts @@ -233,6 +233,7 @@ export const useMultiRunStore = create()( worktreeName: preferredName, startRef: params.worktreeBaseBranch || 'HEAD', setupCommands: commandsToRun, + returnAfterDirectoryCreated: true, }, { resolvedRootTrackingRemote: rootTrackingRemote, }); diff --git a/packages/vscode/CHANGELOG.md b/packages/vscode/CHANGELOG.md index 73a13159..72f498f0 100644 --- a/packages/vscode/CHANGELOG.md +++ b/packages/vscode/CHANGELOG.md @@ -1,3 +1,8 @@ +## [Unreleased] + +- Agent Manager: creating isolated runs now opens sessions immediately while worktree setup continues in the background. +- Sessions: chat folder assignments now stay in place after reloads. + ## [1.12.3] - 2026-06-05 - Startup: OpenCode health checks now work with OpenCode 1.15.x.