1- import { onMount , onCleanup , createEffect } from 'solid-js' ;
1+ import { onMount , onCleanup , createEffect , Show } from 'solid-js' ;
22import { Terminal , type IMarker } from '@xterm/xterm' ;
33import { FitAddon } from '@xterm/addon-fit' ;
44import { WebglAddon } from '@xterm/addon-webgl' ;
@@ -12,7 +12,7 @@ import { matchesGlobalShortcut } from '../lib/shortcuts';
1212import { isMac } from '../lib/platform' ;
1313import { resolvedBindings } from '../store/keybindings' ;
1414import { matchesKeyEvent } from '../lib/keybindings' ;
15- import { store , setTaskLastInputAt } from '../store/store' ;
15+ import { store , setTaskLastInputAt , retryTaskMcpStartup } from '../store/store' ;
1616import { warn as logWarn } from '../lib/log' ;
1717import { registerTerminal , unregisterTerminal , markDirty } from '../lib/terminalFitManager' ;
1818import { dataTransferToShellArgs , escapePath } from '../lib/terminalDrop' ;
@@ -645,16 +645,18 @@ export function TerminalView(props: TerminalViewProps) {
645645 // For coordinator and coordinated sub-tasks, defer spawn until MCP is ready.
646646 // Coordinator tasks wait for StartMCPServer to complete; sub-tasks wait for hydrateTask.
647647 const task = store . tasks [ taskId ] ;
648- if ( ( task ?. coordinatedBy || task ?. coordinatorMode ) && ! task ?. mcpReady ) {
648+ if ( task ?. mcpStartupStatus === 'pending' ) {
649649 let spawned = false ;
650650 createEffect ( ( ) => {
651651 if ( spawned ) return ;
652- if ( store . tasks [ taskId ] ?. mcpReady ) {
652+ const status = store . tasks [ taskId ] ?. mcpStartupStatus ;
653+ if ( status === 'ready' ) {
653654 spawned = true ;
654655 spawnNow ( ) ;
655656 }
657+ // 'error' is handled by the overlay rendered outside onMount
656658 } ) ;
657- } else {
659+ } else if ( task ?. mcpStartupStatus !== 'error' ) {
658660 spawnNow ( ) ;
659661 }
660662
@@ -695,16 +697,62 @@ export function TerminalView(props: TerminalViewProps) {
695697 markDirty ( props . agentId ) ;
696698 } ) ;
697699
700+ const mcpError = ( ) => store . tasks [ props . taskId ] ?. mcpStartupError ;
701+ const mcpStatus = ( ) => store . tasks [ props . taskId ] ?. mcpStartupStatus ;
702+
698703 return (
699- < div
700- ref = { containerRef }
701- style = { {
702- width : '100%' ,
703- height : '100%' ,
704- overflow : 'hidden' ,
705- padding : '4px 0 0 4px' ,
706- contain : 'strict' ,
707- } }
708- />
704+ < div style = { { position : 'relative' , width : '100%' , height : '100%' } } >
705+ < div
706+ ref = { containerRef }
707+ style = { {
708+ width : '100%' ,
709+ height : '100%' ,
710+ overflow : 'hidden' ,
711+ padding : '4px 0 0 4px' ,
712+ contain : 'strict' ,
713+ } }
714+ />
715+ < Show when = { mcpStatus ( ) === 'error' } >
716+ < div
717+ style = { {
718+ position : 'absolute' ,
719+ inset : '0' ,
720+ display : 'flex' ,
721+ 'flex-direction' : 'column' ,
722+ 'align-items' : 'center' ,
723+ 'justify-content' : 'center' ,
724+ gap : '12px' ,
725+ background : 'rgba(0,0,0,0.85)' ,
726+ 'font-family' : 'var(--font-ui)' ,
727+ 'z-index' : '10' ,
728+ } }
729+ >
730+ < span
731+ style = { {
732+ color : '#ff6b6b' ,
733+ 'font-size' : '13px' ,
734+ 'text-align' : 'center' ,
735+ padding : '0 16px' ,
736+ } }
737+ >
738+ MCP startup failed: { mcpError ( ) ?? 'unknown error' }
739+ </ span >
740+ < button
741+ style = { {
742+ padding : '6px 16px' ,
743+ background : '#3b82f6' ,
744+ color : '#fff' ,
745+ border : 'none' ,
746+ 'border-radius' : '4px' ,
747+ 'font-size' : '13px' ,
748+ cursor : 'pointer' ,
749+ } }
750+ onClick = { ( ) => retryTaskMcpStartup ( props . taskId ) }
751+ >
752+ Retry
753+ </ button >
754+ </ div >
755+ </ Show >
756+ </ div >
709757 ) ;
710758}
0 commit comments