@@ -39,10 +39,15 @@ public enum MessageType : int
3939 /// </summary>
4040 RunCommand = 5 ,
4141
42+ /// <summary>
43+ /// A message from AIShell to command-line shell to ask for the result of a previous command run.
44+ /// </summary>
45+ AskCommandOutput = 6 ,
46+
4247 /// <summary>
4348 /// A message from command-line shell to AIShell to post the result of a command.
4449 /// </summary>
45- PostResult = 6 ,
50+ PostResult = 7 ,
4651}
4752
4853/// <summary>
@@ -239,6 +244,27 @@ public RunCommandMessage(string command, bool blocking)
239244 }
240245}
241246
247+ /// <summary>
248+ /// Message for <see cref="MessageType.AskCommandOutput"/>.
249+ /// </summary>
250+ public sealed class AskCommandOutputMessage : PipeMessage
251+ {
252+ /// <summary>
253+ /// Gets the id of the command to retrieve the output for.
254+ /// </summary>
255+ public string CommandId { get ; }
256+
257+ /// <summary>
258+ /// Creates an instance of <see cref="AskCommandOutputMessage"/>.
259+ /// </summary>
260+ public AskCommandOutputMessage ( string commandId )
261+ : base ( MessageType . AskCommandOutput )
262+ {
263+ ArgumentException . ThrowIfNullOrEmpty ( commandId ) ;
264+ CommandId = commandId ;
265+ }
266+ }
267+
242268/// <summary>
243269/// Message for <see cref="MessageType.PostResult"/>.
244270/// </summary>
@@ -426,6 +452,7 @@ private static PipeMessage DeserializePayload(int type, ReadOnlySpan<byte> bytes
426452 ( int ) MessageType . PostContext => JsonSerializer . Deserialize < PostContextMessage > ( bytes ) ,
427453 ( int ) MessageType . PostCode => JsonSerializer . Deserialize < PostCodeMessage > ( bytes ) ,
428454 ( int ) MessageType . RunCommand => JsonSerializer . Deserialize < RunCommandMessage > ( bytes ) ,
455+ ( int ) MessageType . AskCommandOutput => JsonSerializer . Deserialize < AskCommandOutputMessage > ( bytes ) ,
429456 ( int ) MessageType . PostResult => JsonSerializer . Deserialize < PostResultMessage > ( bytes ) ,
430457 _ => throw new NotSupportedException ( "Unreachable code" ) ,
431458 } ;
@@ -550,6 +577,11 @@ public async Task StartProcessingAsync(int timeout, CancellationToken cancellati
550577 SendMessage ( result ) ;
551578 break ;
552579
580+ case MessageType . AskCommandOutput :
581+ var output = InvokeOnAskCommandOutput ( ( AskCommandOutputMessage ) message ) ;
582+ SendMessage ( output ) ;
583+ break ;
584+
553585 default :
554586 // Log: unexpected messages ignored.
555587 break ;
@@ -622,6 +654,9 @@ private PostContextMessage InvokeOnAskContext(AskContextMessage message)
622654 return null ;
623655 }
624656
657+ /// <summary>
658+ /// Helper to invoke the <see cref="OnRunCommand"/> event.
659+ /// </summary>
625660 private PostResultMessage InvokeOnRunCommand ( RunCommandMessage message )
626661 {
627662 if ( OnRunCommand is null )
@@ -649,6 +684,36 @@ private PostResultMessage InvokeOnRunCommand(RunCommandMessage message)
649684 }
650685 }
651686
687+ /// <summary>
688+ /// Helper to invoke the <see cref="OnAskCommandOutput"/> event.
689+ /// </summary>
690+ private PostResultMessage InvokeOnAskCommandOutput ( AskCommandOutputMessage message )
691+ {
692+ if ( OnAskCommandOutput is null )
693+ {
694+ // Log: event handler not set.
695+ return new PostResultMessage (
696+ output : "Retrieving command output is not supported." ,
697+ hadError : true ,
698+ userCancelled : false ,
699+ exception : null ) ;
700+ }
701+
702+ try
703+ {
704+ return OnAskCommandOutput ( message ) ;
705+ }
706+ catch ( Exception e )
707+ {
708+ // Log: exception when invoking 'OnAskCommandOutput'
709+ return new PostResultMessage (
710+ output : "Failed to retrieve the command output due to an internal error." ,
711+ hadError : true ,
712+ userCancelled : false ,
713+ exception : e . Message ) ;
714+ }
715+ }
716+
652717 /// <summary>
653718 /// Event for handling the <see cref="MessageType.PostCode"/> message.
654719 /// </summary>
@@ -668,6 +733,11 @@ private PostResultMessage InvokeOnRunCommand(RunCommandMessage message)
668733 /// Event for handling the <see cref="MessageType.RunCommand"/> message.
669734 /// </summary>
670735 public event Func < RunCommandMessage , PostResultMessage > OnRunCommand ;
736+
737+ /// <summary>
738+ /// Event for handling the <see cref="MessageType.AskCommandOutput"/> message.
739+ /// </summary>
740+ public event Func < AskCommandOutputMessage , PostResultMessage > OnAskCommandOutput ;
671741}
672742
673743/// <summary>
@@ -889,6 +959,13 @@ public async Task<PostContextMessage> AskContext(AskContextMessage message, Canc
889959 return postContext ;
890960 }
891961
962+ /// <summary>
963+ /// Run a command in the connected PowerShell session.
964+ /// </summary>
965+ /// <param name="message">The <see cref="MessageType.RunCommand"/> message.</param>
966+ /// <param name="cancellationToken">A cancellation token.</param>
967+ /// <returns>A <see cref="MessageType.PostResult"/> message as the response.</returns>
968+ /// <exception cref="IOException">Throws when the pipe is closed by the other side.</exception>
892969 public async Task < PostResultMessage > RunCommand ( RunCommandMessage message , CancellationToken cancellationToken )
893970 {
894971 // Send the request message to the shell.
@@ -905,4 +982,28 @@ public async Task<PostResultMessage> RunCommand(RunCommandMessage message, Cance
905982
906983 return postResult ;
907984 }
985+
986+ /// <summary>
987+ /// Ask for the output of a previously run command in the connected PowerShell session.
988+ /// </summary>
989+ /// <param name="message">The <see cref="MessageType.AskCommandOutput"/> message.</param>
990+ /// <param name="cancellationToken">A cancellation token.</param>
991+ /// <returns>A <see cref="MessageType.PostResult"/> message as the response.</returns>
992+ /// <exception cref="IOException">Throws when the pipe is closed by the other side.</exception>
993+ public async Task < PostResultMessage > AskCommandOutput ( AskCommandOutputMessage message , CancellationToken cancellationToken )
994+ {
995+ // Send the request message to the shell.
996+ SendMessage ( message ) ;
997+
998+ // Receiving response from the shell.
999+ var response = await GetMessageAsync ( cancellationToken ) ;
1000+ if ( response is not PostResultMessage postResult )
1001+ {
1002+ // Log: unexpected message. drop connection.
1003+ _client . Close ( ) ;
1004+ throw new IOException ( $ "Expecting '{ MessageType . PostResult } ' response, but received '{ message . Type } ' message.") ;
1005+ }
1006+
1007+ return postResult ;
1008+ }
9081009}
0 commit comments