@@ -63,6 +63,7 @@ public sealed class DapDebugger : RunnerService, IDapDebugger
6363 private volatile DapSessionState _state = DapSessionState . NotStarted ;
6464 private CancellationTokenRegistration ? _cancellationRegistration ;
6565 private bool _isFirstStep = true ;
66+ private bool _welcomeMessageSent ;
6667
6768 // Dev Tunnel relay host for remote debugging
6869 private TunnelRelayTunnelHost _tunnelRelayHost ;
@@ -490,6 +491,11 @@ internal async Task HandleMessageAsync(string messageJson, CancellationToken can
490491 } ) ;
491492 Trace . Info ( "Sent initialized event" ) ;
492493 }
494+
495+ if ( request . Command == "configurationDone" )
496+ {
497+ SendWelcomeMessage ( ) ;
498+ }
493499 }
494500 catch ( Exception ex )
495501 {
@@ -508,6 +514,7 @@ internal async Task HandleMessageAsync(string messageJson, CancellationToken can
508514 internal void HandleClientConnected ( )
509515 {
510516 _isClientConnected = true ;
517+ _welcomeMessageSent = false ;
511518 Trace . Info ( "Client connected to debug session" ) ;
512519
513520 // If we're paused, re-send the stopped event so the new client
@@ -818,6 +825,34 @@ private void SendOutput(string category, string text)
818825 } ) ;
819826 }
820827
828+ internal void SendWelcomeMessage ( )
829+ {
830+ if ( _welcomeMessageSent )
831+ {
832+ return ;
833+ }
834+ _welcomeMessageSent = true ;
835+
836+ var debuggerConfig = _jobContext ? . Global ? . Debugger ;
837+ if ( debuggerConfig ? . OverrideWelcomeMessage == true )
838+ {
839+ if ( ! string . IsNullOrEmpty ( debuggerConfig . WelcomeMessage ) )
840+ {
841+ SendOutput ( "console" , debuggerConfig . WelcomeMessage ) ;
842+ Trace . Info ( "Sent custom welcome message" ) ;
843+ }
844+ else
845+ {
846+ Trace . Info ( "Welcome message suppressed by override" ) ;
847+ }
848+ }
849+ else
850+ {
851+ SendOutput ( "console" , DapReplParser . GetGeneralHelp ( ) ) ;
852+ Trace . Info ( "Sent default welcome message" ) ;
853+ }
854+ }
855+
821856 internal async Task OnStepStartingAsync ( IStep step , bool isFirstStep )
822857 {
823858 bool pauseOnNextStep ;
@@ -860,6 +895,9 @@ internal async Task OnStepStartingAsync(IStep step, bool isFirstStep)
860895 // Send stopped event to debugger (only if client is connected)
861896 SendStoppedEvent ( reason , description ) ;
862897
898+ // Emit a banner so the user knows where REPL commands will execute
899+ SendExecutionContextBanner ( ) ;
900+
863901 // Wait for debugger command
864902 await WaitForCommandAsync ( cancellationToken ) ;
865903 }
@@ -1195,7 +1233,12 @@ private async Task<EvaluateResponseBody> DispatchReplCommandAsync(
11951233
11961234 case RunCommand run :
11971235 var context = GetExecutionContextForFrame ( frameId ) ;
1198- return await _replExecutor . ExecuteRunCommandAsync ( run , context , cancellationToken ) ;
1236+ bool isActionStep ;
1237+ lock ( _stateLock )
1238+ {
1239+ isActionStep = _currentStep is IActionRunner ;
1240+ }
1241+ return await _replExecutor . ExecuteRunCommandAsync ( run , context , isActionStep , cancellationToken ) ;
11991242
12001243 default :
12011244 return new EvaluateResponseBody
@@ -1407,6 +1450,40 @@ private void SendStoppedEvent(string reason, string description)
14071450 } ) ;
14081451 }
14091452
1453+ /// <summary>
1454+ /// Emits a console output banner telling the user whether REPL
1455+ /// commands will execute on the host or inside the job container.
1456+ /// </summary>
1457+ private void SendExecutionContextBanner ( )
1458+ {
1459+ if ( ! _isClientConnected )
1460+ {
1461+ return ;
1462+ }
1463+
1464+ bool isActionStep = _currentStep is IActionRunner ;
1465+ var container = _jobContext ? . Global ? . Container ;
1466+
1467+ string target ;
1468+ if ( isActionStep && container != null &&
1469+ ( ! string . IsNullOrEmpty ( container . ContainerId ) ||
1470+ FeatureManager . IsContainerHooksEnabled ( _jobContext ? . Global ? . Variables ) ) )
1471+ {
1472+ var image = container . ContainerImage ?? "container" ;
1473+ var shortId = ! string . IsNullOrEmpty ( container . ContainerId ) && container . ContainerId . Length >= 12
1474+ ? container . ContainerId . Substring ( 0 , 12 )
1475+ : container . ContainerId ?? "" ;
1476+ var idSuffix = ! string . IsNullOrEmpty ( shortId ) ? $ " ({ shortId } )" : "" ;
1477+ target = $ "job container: { image } { idSuffix } ";
1478+ }
1479+ else
1480+ {
1481+ target = "runner host" ;
1482+ }
1483+
1484+ SendOutput ( "console" , $ "\n Commands will run on { target } \n ") ;
1485+ }
1486+
14101487 private string MaskUserVisibleText ( string value )
14111488 {
14121489 if ( string . IsNullOrEmpty ( value ) )
0 commit comments