/// <summary>
        /// <see cref="IAgentRunnerProvider.RunAsync(AgentRunnerProviderArgs)"/>
        /// </summary>
        public Task RunAsync(AgentRunnerProviderArgs providerArgs)
        {
            var processWrapper = new ProcessWrapper();

            this.backgroundTaskQueue.QueueAgentRun(new AgentRunnerProcess(providerArgs.Channel, processWrapper, async(CancellationToken token) =>
            {
                try
                {
                    if (!providerArgs.AllowSkip || !await providerArgs.SkipHandlerAsync(new AgentRunnerProviderResult
                    {
                        AgentRunner = providerArgs.AgentRunner,
                        Channel = providerArgs.Channel,
                        Command = providerArgs.Command,
                        AgentRunnerType = providerArgs.AgentRunnerType,
                        CancellationToken = token
                    }))
                    {
                        await providerArgs.BeginHandlerAsync(new AgentRunnerProviderResult
                        {
                            AgentRunner       = providerArgs.AgentRunner,
                            Channel           = providerArgs.Channel,
                            Command           = providerArgs.Command,
                            CancellationToken = token
                        });

                        processWrapper.Start(providerArgs.Command);

                        var lineCount = 1;
                        var script    = providerArgs.AgentRunner.Agent.Script;

                        while (!processWrapper.EndOfStream)
                        {
                            if (processWrapper.Stopped)
                            {
                                break;
                            }

                            token.ThrowIfCancellationRequested();

                            // Parse the terminal output one line
                            var terminalLineOutput = processWrapper.TerminalLineOutput();
                            var scriptOutput       = await this.scriptEngineService.TerminalOutputParseAsync(script, terminalLineOutput, lineCount++);

                            await providerArgs.ParserOutputHandlerAsync(new AgentRunnerProviderResult
                            {
                                AgentRunner        = providerArgs.AgentRunner,
                                AgentRunnerType    = providerArgs.AgentRunnerType,
                                Channel            = providerArgs.Channel,
                                ScriptOutput       = scriptOutput,
                                LineCount          = lineCount,
                                TerminalLineOutput = terminalLineOutput,
                                CancellationToken  = token
                            });
                        }
                    }
                    ;

                    await providerArgs.EndHandlerAsync(new AgentRunnerProviderResult
                    {
                        AgentRunner       = providerArgs.AgentRunner,
                        Channel           = providerArgs.Channel,
                        AgentRunnerType   = providerArgs.AgentRunnerType,
                        Command           = providerArgs.Command,
                        Last              = providerArgs.Last,
                        CancellationToken = token
                    });
                }
                catch (Exception ex)
                {
                    await providerArgs.ExceptionHandlerAsync(new AgentRunnerProviderResult
                    {
                        AgentRunner       = providerArgs.AgentRunner,
                        Channel           = providerArgs.Channel,
                        Last              = providerArgs.Last,
                        Command           = providerArgs.Command,
                        Exception         = ex,
                        CancellationToken = token
                    });
                }
            }));

            return(Task.CompletedTask);
        }