From 47937e28d0ce3192f14a3cea330c90b6a9ae7500 Mon Sep 17 00:00:00 2001 From: Merge Sim Date: Sun, 6 Sep 2026 14:13:34 -0700 Subject: [PATCH] Fix background native chat setup terminal seeding --- .../lib/worktree-creation-chat-setup.test.ts | 84 +++++++++++++++++++ .../src/lib/worktree-creation-flow-execute.ts | 1 + 2 files changed, 85 insertions(+) create mode 100644 src/renderer/src/lib/worktree-creation-chat-setup.test.ts diff --git a/src/renderer/src/lib/worktree-creation-chat-setup.test.ts b/src/renderer/src/lib/worktree-creation-chat-setup.test.ts new file mode 100644 index 00000000000..3c6be8b26af --- /dev/null +++ b/src/renderer/src/lib/worktree-creation-chat-setup.test.ts @@ -0,0 +1,84 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { useAppStore } from '@/store' +import { executeWorktreeCreation } from './worktree-creation-flow-execute' +import { launchStructuredWorktreeSession } from './worktree-creation-structured-session' +import { + makeCreatedAgentWorktree, + seedEmptyActivatableWorktree +} from './worktree-activation-created-agent-test-state' +import { registerWorktreeActivationReset } from './worktree-activation-test-harness' +import type { WorktreeCreationRequest } from './pending-worktree-creation' + +vi.mock('./worktree-creation-structured-session', () => ({ + launchStructuredWorktreeSession: vi.fn(async (args) => ({ + accepted: true, + cancelled: false, + visibilityUnknown: false, + activation: args.activation, + primaryTabId: args.primaryTabId + })) +})) +vi.mock('./worktree-creation-completion', () => ({ completeWorktreeCreation: vi.fn() })) + +const initialState = useAppStore.getState() +registerWorktreeActivationReset() +afterEach(() => { + vi.restoreAllMocks() + useAppStore.setState(initialState, true) +}) + +describe('native chat creation completed in the background', () => { + it.each(['claude', 'codex'] as const)( + 'runs setup once without an idle shell or focus change for %s', + async (agent) => { + const worktree = makeCreatedAgentWorktree() + seedEmptyActivatableWorktree(worktree) + const request: WorktreeCreationRequest = { + repoId: worktree.repoId, + name: 'feature', + setupDecision: 'run', + agent, + agentLaunchRoute: 'structured-native-chat', + pendingFirstAgentMessageRename: false, + note: '', + startupPlan: null, + quickPrompt: '', + quickTelemetry: null + } + const setup = { runnerScriptPath: '/tmp/setup-runner.sh', envVars: {} } + useAppStore.setState({ + activeView: 'tasks', + activeWorktreeId: 'previous-worktree', + activeTabId: 'previous-tab', + createWorktree: vi.fn().mockResolvedValue({ worktree, setup }), + pendingWorktreeCreations: { + 'creation-1': { + creationId: 'creation-1', + phase: 'fetching', + status: 'creating', + startedAt: 1, + indeterminate: false, + loaderVisible: true, + request + } + } + }) + + await executeWorktreeCreation('creation-1', request) + + const state = useAppStore.getState() + const tabs = state.tabsByWorktree[worktree.id] + expect(tabs).toHaveLength(1) + expect(tabs[0].customTitle).toBe('Setup') + expect(state.pendingStartupByTabId[tabs[0].id]).toMatchObject({ + command: 'bash /tmp/setup-runner.sh' + }) + expect(state.activeView).toBe('tasks') + expect(state.activeWorktreeId).toBe('previous-worktree') + expect(state.activeTabId).toBe('previous-tab') + expect(launchStructuredWorktreeSession).toHaveBeenCalledWith( + expect.objectContaining({ primaryTabId: null, shouldActivateOnCompletion: false }) + ) + } + ) +}) diff --git a/src/renderer/src/lib/worktree-creation-flow-execute.ts b/src/renderer/src/lib/worktree-creation-flow-execute.ts index 9b6ba569b1e..297ebc378a5 100644 --- a/src/renderer/src/lib/worktree-creation-flow-execute.ts +++ b/src/renderer/src/lib/worktree-creation-flow-execute.ts @@ -203,6 +203,7 @@ export async function executeWorktreeCreation( result.defaultTabs, { activateCreatedTabs: false, + ...(structuredLaunch ? { callerProvidesSurface: true } : {}), ...(backendSpawned ? { backendStartupTerminalSpawned: true } : {}) } )