Skip to content

Commit cd64794

Browse files
committed
fix: use queueMicrotask for deploy-to-harness transition in TUI dev
The derived effectiveMode approach didn't trigger re-renders, leaving the deploy screen stuck after completion. Switch to queueMicrotask + setMode (matching the preview branch pattern) so the transition fires correctly. Also handles browser mode by calling onLaunchBrowser after deploy.
1 parent 8341521 commit cd64794

1 file changed

Lines changed: 18 additions & 7 deletions

File tree

src/cli/tui/screens/dev/DevScreen.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,10 @@ export function DevScreen(props: DevScreenProps) {
185185

186186
setAgentsLoaded(true);
187187

188-
// If onLaunchBrowser is set and we can auto-select, do it immediately
189-
if (onLaunchBrowser && agents.length + harnesses.length === 1) {
190-
const agentName = agents.length === 1 ? agents[0]?.name : undefined;
191-
const harnessName = harnesses.length === 1 ? harnesses[0] : undefined;
192-
queueMicrotask(() => onLaunchBrowser({ agentName, harnessName }));
188+
// If onLaunchBrowser is set and only agents (no harnesses), auto-select immediately.
189+
// Harness projects need deploy first — handled after deploy completes.
190+
if (onLaunchBrowser && agents.length === 1 && harnesses.length === 0) {
191+
queueMicrotask(() => onLaunchBrowser({ agentName: agents[0]?.name }));
193192
}
194193
};
195194
void load();
@@ -237,7 +236,19 @@ export function DevScreen(props: DevScreenProps) {
237236
error: deployError,
238237
} = useDevDeploy({ skip: props.skipDeploy, ready: mode === 'deploying' });
239238

240-
const effectiveMode = mode === 'deploying' && deployComplete && !deployError ? 'harness' : mode;
239+
const hasTransitionedFromDeployRef = useRef(false);
240+
useEffect(() => {
241+
if (mode !== 'deploying' || !deployComplete || deployError || hasTransitionedFromDeployRef.current) return;
242+
hasTransitionedFromDeployRef.current = true;
243+
queueMicrotask(() => {
244+
if (onLaunchBrowser) {
245+
onLaunchBrowser({ harnessName: selectedHarness });
246+
} else {
247+
setMode('harness');
248+
}
249+
});
250+
// eslint-disable-next-line react-hooks/exhaustive-deps
251+
}, [mode, deployComplete, deployError]);
241252

242253
// MCP: auto-list tools when server becomes ready, show hint in conversation
243254
const mcpFetchTriggeredRef = useRef(false);
@@ -517,7 +528,7 @@ export function DevScreen(props: DevScreenProps) {
517528
}
518529

519530
// If harness mode (preview), render the InvokeScreen with the pre-selected harness
520-
if (preview && effectiveMode === 'harness') {
531+
if (preview && mode === 'harness') {
521532
return <InvokeScreen isInteractive={true} onExit={handleExit} title="Dev" initialHarnessName={selectedHarness} />;
522533
}
523534

0 commit comments

Comments
 (0)