コード例 #1
0
        public static Parser Create(
            IServiceCollection services,
            StartServer startServer             = null,
            Jupyter jupyter                     = null,
            StartKernelServer startKernelServer = null,
            ITelemetry telemetry                = null,
            IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            startServer ??= ((startupOptions, invocationContext) =>
                             Program.ConstructWebHost(startupOptions).Run());

            jupyter ??= JupyterCommand.Do;

            startKernelServer ??= (async(startupOptions, kernel, console) =>
            {
                var disposable = Program.StartToolLogging(startupOptions);
                if (kernel is KernelBase kernelBase)
                {
                    kernelBase.RegisterForDisposal(disposable);
                }
                var server = new StandardIOKernelServer(
                    kernel,
                    Console.In,
                    Console.Out);

                await server.Input.LastAsync();
            });

            // Setup first time use notice sentinel.
            firstTimeUseNoticeSentinel ??= new FirstTimeUseNoticeSentinel(VersionSensor.Version().AssemblyInformationalVersion);

            // Setup telemetry.
            telemetry ??= new Telemetry.Telemetry(
                VersionSensor.Version().AssemblyInformationalVersion,
                firstTimeUseNoticeSentinel);
            var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);

            void Track(ParseResult o) => telemetry.SendFiltered(filter, o);

            var verboseOption = new Option <bool>(
                "--verbose",
                "Enable verbose logging to the console");

            var logPathOption = new Option <DirectoryInfo>(
                "--log-path",
                "Enable file logging to the specified directory");

            var defaultKernelOption = new Option <string>(
                "--default-kernel",
                description: "The default language for the kernel",
                getDefaultValue: () => "csharp");
            var rootCommand = DotnetInteractive();

            rootCommand.AddCommand(Jupyter());
            rootCommand.AddCommand(KernelServer());

            return(new CommandLineBuilder(rootCommand)
                   .UseDefaults()
                   .UseMiddleware(async(context, next) =>
            {
                // If sentinel does not exist, print the welcome message showing the telemetry notification.
                if (!firstTimeUseNoticeSentinel.Exists() && !Telemetry.Telemetry.SkipFirstTimeExperience)
                {
                    context.Console.Out.WriteLine();
                    context.Console.Out.WriteLine(Telemetry.Telemetry.WelcomeMessage);

                    firstTimeUseNoticeSentinel.CreateIfNotExists();
                }

                await next(context);
            })
                   .Build());

            RootCommand DotnetInteractive()
            {
                var command = new RootCommand
                {
                    Name        = "dotnet-interactive",
                    Description = "Interactive programming for .NET."
                };

                command.AddOption(logPathOption);
                command.AddOption(verboseOption);

                return(command);
            }

            Command Jupyter()
            {
                var jupyterCommand = new Command("jupyter", "Starts dotnet-interactive as a Jupyter kernel")
                {
                    defaultKernelOption,
                    logPathOption,
                    verboseOption,
                    new Argument <FileInfo>
                    {
                        Name = "connection-file"
                    }.ExistingOnly()
                };

                jupyterCommand.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>((startupOptions, options, console, context) =>
                {
                    Track(context.ParseResult);

                    services
                    .AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile))
                    .AddSingleton(
                        c =>
                    {
                        return(CommandScheduler
                               .Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >()
                                                               .Trace()
                                                               .Handle(delivery)));
                    })
                    .AddSingleton(c => CreateKernel(options.DefaultKernel))
                    .AddSingleton(c => new JupyterRequestContextHandler(c.GetRequiredService <IKernel>())
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>();

                    return(jupyter(startupOptions, console, startServer, context));
                });

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter")
                {
                    logPathOption,
                    verboseOption
                };

                installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext>((console, context) =>
                {
                    Track(context.ParseResult);
                    return(new JupyterInstallCommand(console, new JupyterKernelSpec()).InvokeAsync());
                });

                jupyterCommand.AddCommand(installCommand);

                return(jupyterCommand);
            }

            Command KernelServer()
            {
                var startKernelServerCommand = new Command("kernel-server", "Starts dotnet-interactive with kernel functionality exposed over standard I/O")
                {
                    defaultKernelOption,
                    logPathOption,
                };

                startKernelServerCommand.Handler = CommandHandler.Create <StartupOptions, KernelServerOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    Track(context.ParseResult);
                    return(startKernelServer(startupOptions, CreateKernel(options.DefaultKernel), console));
                });

                return(startKernelServerCommand);
            }
        }
コード例 #2
0
ファイル: CommandLineParser.cs プロジェクト: stecome/try
        public static Parser Create(
            IServiceCollection services,
            StartServer startServer = null,
            Demo demo           = null,
            TryGitHub tryGithub = null,
            Pack pack           = null,
            Install install     = null,
            Verify verify       = null,
            Jupyter jupyter     = null,
            StartKernelServer startKernelServer = null,
            ITelemetry telemetry = null,
            IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            startServer = startServer ??
                          ((startupOptions, invocationContext) =>
                           Program.ConstructWebHost(startupOptions).Run());

            jupyter = jupyter ??
                      ((startupOptions, console, server, context) =>
                       JupyterCommand.Do(startupOptions, console, server, context));

            demo = demo ??
                   DemoCommand.Do;

            tryGithub = tryGithub ??
                        ((repo, console) =>
                         GitHubHandler.Handler(repo,
                                               console,
                                               new GitHubRepoLocator()));

            verify = verify ??
                     ((options, console, startupOptions) =>
                      VerifyCommand.Do(options,
                                       console,
                                       startupOptions));

            pack = pack ??
                   PackCommand.Do;

            install = install ??
                      InstallCommand.Do;

            startKernelServer = startKernelServer ??
                                ((startupOptions, kernel, console) =>
                                 KernelServerCommand.Do(startupOptions, kernel, console));

            // Setup first time use notice sentinel.
            firstTimeUseNoticeSentinel = firstTimeUseNoticeSentinel ?? new FirstTimeUseNoticeSentinel();

            // Setup telemetry.
            telemetry = telemetry ?? new Telemetry.Telemetry(firstTimeUseNoticeSentinel);
            var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);
            Action <ParseResult> track = o => telemetry.SendFiltered(filter, o);

            var dirArgument = new Argument <FileSystemDirectoryAccessor>(() => new FileSystemDirectoryAccessor(Directory.GetCurrentDirectory()))
            {
                Name        = nameof(StartupOptions.RootDirectory),
                Arity       = ArgumentArity.ZeroOrOne,
                Description = "Specify the path to the root directory for your documentation",
            };

            dirArgument.AddValidator(symbolResult =>
            {
                var directory = symbolResult.Tokens
                                .Select(t => t.Value)
                                .FirstOrDefault();

                if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                {
                    return($"Directory does not exist: {directory}");
                }

                return(null);
            });

            var rootCommand = StartInTryMode();

            rootCommand.AddCommand(StartInHostedMode());
            rootCommand.AddCommand(Demo());
            rootCommand.AddCommand(GitHub());
            rootCommand.AddCommand(Pack());
            rootCommand.AddCommand(Install());
            rootCommand.AddCommand(Verify());
            rootCommand.AddCommand(Jupyter());
            rootCommand.AddCommand(KernelServer());

            return(new CommandLineBuilder(rootCommand)
                   .UseDefaults()
                   .UseMiddleware(async(context, next) =>
            {
                // If sentinel does not exist, print the welcome message showing the telemetry notification.
                if (!firstTimeUseNoticeSentinel.Exists() && !Telemetry.Telemetry.SkipFirstTimeExperience)
                {
                    context.Console.Out.WriteLine();
                    context.Console.Out.WriteLine(Telemetry.Telemetry.WelcomeMessage);

                    firstTimeUseNoticeSentinel.CreateIfNotExists();
                }

                if (context.ParseResult.Directives.Contains("debug") &&
                    !(Clock.Current is VirtualClock))
                {
                    VirtualClock.Start();
                }

                await next(context);
            })
                   .Build());

            RootCommand StartInTryMode()
            {
                var command = new RootCommand
                {
                    Name        = "dotnet-try",
                    Description = "Interactive documentation in your browser"
                };

                command.AddArgument(dirArgument);

                command.AddOption(new Option(
                                      "--add-package-source",
                                      "Specify an additional NuGet package source")
                {
                    Argument = new Argument <PackageSource>(() => new PackageSource(Directory.GetCurrentDirectory()))
                    {
                        Name = "NuGet source"
                    }
                });

                command.AddOption(new Option(
                                      "--package",
                                      "Specify a Try .NET package or path to a .csproj to run code samples with")
                {
                    Argument = new Argument <string>
                    {
                        Name = "name or .csproj"
                    }
                });

                command.AddOption(new Option(
                                      "--package-version",
                                      "Specify a Try .NET package version to use with the --package option")
                {
                    Argument = new Argument <string>
                    {
                        Name = "version"
                    }
                });

                command.AddOption(new Option(
                                      "--uri",
                                      "Specify a URL or a relative path to a Markdown file")
                {
                    Argument = new Argument <Uri>()
                });

                command.AddOption(new Option(
                                      "--enable-preview-features",
                                      "Enable preview features")
                {
                    Argument = new Argument <bool>()
                });

                command.AddOption(new Option(
                                      "--log-path",
                                      "Enable file logging to the specified directory")
                {
                    Argument = new Argument <DirectoryInfo>
                    {
                        Name = "dir"
                    }
                });

                command.AddOption(new Option(
                                      "--verbose",
                                      "Enable verbose logging to the console")
                {
                    Argument = new Argument <bool>()
                });

                var portArgument = new Argument <ushort>();

                portArgument.AddValidator(symbolResult =>
                {
                    if (symbolResult.Tokens
                        .Select(t => t.Value)
                        .Count(value => !ushort.TryParse(value, out _)) > 0)
                    {
                        return("Invalid argument for --port option");
                    }

                    return(null);
                });

                command.AddOption(new Option(
                                      "--port",
                                      "Specify the port for dotnet try to listen on")
                {
                    Argument = portArgument
                });

                command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) =>
                {
                    services.AddSingleton(_ => PackageRegistry.CreateForTryMode(
                                              options.RootDirectory,
                                              options.AddPackageSource));

                    startServer(options, context);
                });

                return(command);
            }

            Command StartInHostedMode()
            {
                var command = new Command("hosted")
                {
                    new Option(
                        "--id",
                        "A unique id for the agent instance (e.g. its development environment id).")
                    {
                        Argument = new Argument <string>(defaultValue: () => Environment.MachineName)
                    },
                    new Option(
                        "--production",
                        "Specifies whether the agent is being run using production resources")
                    {
                        Argument = new Argument <bool>()
                    },
                    new Option(
                        "--language-service",
                        "Specifies whether the agent is being run in language service-only mode")
                    {
                        Argument = new Argument <bool>()
                    },
                    new Option(
                        new[]
                    {
                        "-k",
                        "--key"
                    },
                        "The encryption key")
                    {
                        Argument = new Argument <string>()
                    },
                    new Option(
                        new[]
                    {
                        "--ai-key",
                        "--application-insights-key"
                    },
                        "Application Insights key.")
                    {
                        Argument = new Argument <string>()
                    },
                    new Option(
                        "--region-id",
                        "A unique id for the agent region")
                    {
                        Argument = new Argument <string>()
                    },
                    new Option(
                        "--log-to-file",
                        "Writes a log file")
                    {
                        Argument = new Argument <bool>()
                    }
                };

                command.Description = "Starts the Try .NET agent";

                command.IsHidden = true;

                command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) =>
                {
                    services.AddSingleton(_ => PackageRegistry.CreateForHostedMode());
                    services.AddSingleton(c => new MarkdownProject(c.GetRequiredService <PackageRegistry>()));
                    services.AddSingleton <IHostedService, Warmup>();

                    startServer(options, context);
                });

                return(command);
            }

            Command Demo()
            {
                var demoCommand = new Command(
                    "demo",
                    "Learn how to create Try .NET content with an interactive demo")
                {
                    new Option("--output", "Where should the demo project be written to?")
                    {
                        Argument = new Argument <DirectoryInfo>(
                            defaultValue: () => new DirectoryInfo(Directory.GetCurrentDirectory()))
                    }
                };

                demoCommand.Handler = CommandHandler.Create <DemoOptions, InvocationContext>((options, context) =>
                {
                    demo(options, context.Console, startServer, context);
                });

                return(demoCommand);
            }

            Command GitHub()
            {
                var argument = new Argument <string>
                {
                    // System.CommandLine parameter binding does lookup by name,
                    // so name the argument after the github command's string param
                    Name = nameof(TryGitHubOptions.Repo)
                };

                var github = new Command("github", "Try a GitHub repo")
                {
                    argument
                };

                github.IsHidden = true;

                github.Handler = CommandHandler.Create <TryGitHubOptions, IConsole>((repo, console) => tryGithub(repo, console));

                return(github);
            }

            Command Jupyter()
            {
                var jupyterCommand      = new Command("jupyter", "Starts dotnet try as a Jupyter kernel");
                var defaultKernelOption = new Option("--default-kernel", "The default .NET kernel language for the notebook.")
                {
                    Argument = new Argument <string>(defaultValue: () => "csharp")
                };

                jupyterCommand.AddOption(defaultKernelOption);
                var connectionFileArgument = new Argument <FileInfo>
                {
                    Name  = "ConnectionFile",
                    Arity = ArgumentArity.ZeroOrOne //should be removed once the commandlineapi allows subcommands to not have arguments from the main command
                }.ExistingOnly();

                jupyterCommand.AddArgument(connectionFileArgument);

                jupyterCommand.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>((startupOptions, options, console, context) =>
                {
                    track(context.ParseResult);

                    services
                    .AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile))
                    .AddSingleton(
                        c =>
                    {
                        return(CommandScheduler
                               .Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >()
                                                               .Trace()
                                                               .Handle(delivery)));
                    })
                    .AddSingleton(c => CreateKernel(options.DefaultKernel))
                    .AddSingleton(c => new JupyterRequestContextHandler(c.GetRequiredService <IKernel>())
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>();

                    return(jupyter(startupOptions, console, startServer, context));
                });

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter");

                installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext>((console, context) =>
                {
                    track(context.ParseResult);
                    return(new JupyterCommandLine(console, new FileSystemJupyterKernelSpec()).InvokeAsync());
                });

                jupyterCommand.AddCommand(installCommand);

                return(jupyterCommand);
            }

            Command KernelServer()
            {
                var startKernelServerCommand = new Command("kernel-server", "Starts dotnet-try with kernel functionality exposed over standard I/O");
                var defaultKernelOption      = new Option("--default-kernel", "The default .NET kernel language for the notebook.")
                {
                    Argument = new Argument <string>(defaultValue: () => "csharp")
                };

                startKernelServerCommand.AddOption(defaultKernelOption);

                startKernelServerCommand.Handler = CommandHandler.Create <StartupOptions, KernelServerOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    track(context.ParseResult);
                    return(startKernelServer(startupOptions, CreateKernel(options.DefaultKernel), console));
                });

                return(startKernelServerCommand);
            }

            Command Pack()
            {
                var packCommand = new Command("pack", "Create a Try .NET package")
                {
                    new Argument <DirectoryInfo>
                    {
                        Name = nameof(PackOptions.PackTarget)
                    },
                    new Option("--version", "The version of the Try .NET package")
                    {
                        Argument = new Argument <string>()
                    },
                    new Option("--enable-wasm", "Enables web assembly code execution")
                };

                packCommand.IsHidden = true;

                packCommand.Handler = CommandHandler.Create <PackOptions, IConsole>(
                    (options, console) =>
                {
                    return(pack(options, console));
                });

                return(packCommand);
            }

            Command Install()
            {
                var installCommand = new Command("install", "Install a Try .NET package")
                {
                    new Argument <string>
                    {
                        Name  = nameof(InstallOptions.PackageName),
                        Arity = ArgumentArity.ExactlyOne
                    },
                    new Option("--add-source")
                    {
                        Argument = new Argument <PackageSource>()
                    }
                };

                installCommand.IsHidden = true;

                installCommand.Handler = CommandHandler.Create <InstallOptions, IConsole>((options, console) => install(options, console));

                return(installCommand);
            }

            Command Verify()
            {
                var verifyCommand = new Command("verify", "Verify Markdown files in the target directory and its children.")
                {
                    dirArgument
                };

                verifyCommand.Handler = CommandHandler.Create <VerifyOptions, IConsole, StartupOptions>(
                    (options, console, startupOptions) =>
                {
                    return(verify(options, console, startupOptions));
                });

                return(verifyCommand);
            }
        }
コード例 #3
0
        public static Parser Create(
            IServiceCollection services,
            StartServer startServer             = null,
            Jupyter jupyter                     = null,
            StartKernelServer startKernelServer = null,
            ITelemetry telemetry                = null,
            IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            startServer ??= (startupOptions, invocationContext) =>
            Program.ConstructWebHost(startupOptions).Run();

            jupyter ??= JupyterCommand.Do;

            startKernelServer ??= async(startupOptions, kernel, console) =>
            {
                var disposable = Program.StartToolLogging(startupOptions);

                if (kernel is KernelBase kernelBase)
                {
                    kernelBase.RegisterForDisposal(disposable);
                }

                var server = new StandardIOKernelServer(
                    kernel,
                    Console.In,
                    Console.Out);

                await server.Input.LastAsync();
            };

            // Setup first time use notice sentinel.
            firstTimeUseNoticeSentinel ??= new FirstTimeUseNoticeSentinel(VersionSensor.Version().AssemblyInformationalVersion);

            // Setup telemetry.
            telemetry ??= new Telemetry.Telemetry(
                VersionSensor.Version().AssemblyInformationalVersion,
                firstTimeUseNoticeSentinel);
            var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);

            var verboseOption = new Option <bool>(
                "--verbose",
                "Enable verbose logging to the console");

            var httpPortOption = new Option <int>(
                "--http-port",
                "Specifies the port on which to enable HTTP services");

            var httpPortRangeOption = new Option <PortRange>(
                "--http-port-range",
                parseArgument: result =>
            {
                if (result.Parent.Parent.Children.FirstOrDefault(c => c.Symbol == httpPortOption) is OptionResult conflictingOption)
                {
                    var parsed          = result.Parent as OptionResult;
                    result.ErrorMessage = $"Cannot specify both {conflictingOption.Token.Value} and {parsed.Token.Value} together";
                    return(null);
                }

                var source = result.Tokens[0].Value;

                if (string.IsNullOrWhiteSpace(source))
                {
                    result.ErrorMessage = "Must specify a port range";
                    return(null);
                }

                var parts = source.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries);

                if (parts.Length != 2)
                {
                    result.ErrorMessage = "Must specify a port range";
                    return(null);
                }

                if (!int.TryParse(parts[0], out var start) || !int.TryParse(parts[1], out var end))
                {
                    result.ErrorMessage = "Must specify a port range as StartPort-EndPort";

                    return(null);
                }

                if (start > end)
                {
                    result.ErrorMessage = "Start port must be lower then end port";
                    return(null);
                }

                var pr = new PortRange(start, end);

                return(pr);
            },
                description: "Specifies the range of port to use to enable HTTP services");

            var logPathOption = new Option <DirectoryInfo>(
                "--log-path",
                "Enable file logging to the specified directory");

            var pathOption = new Option <DirectoryInfo>(
                "--path",
                "Installs the kernelspecs to the specified directory")
                             .ExistingOnly();

            var defaultKernelOption = new Option <string>(
                "--default-kernel",
                description: "The default language for the kernel",
                getDefaultValue: () => "csharp");

            var rootCommand = DotnetInteractive();

            rootCommand.AddCommand(Jupyter());
            rootCommand.AddCommand(KernelServer());
            rootCommand.AddCommand(HttpServer());

            return(new CommandLineBuilder(rootCommand)
                   .UseDefaults()
                   .UseMiddleware(async(context, next) =>
            {
                if (context.ParseResult.Errors.Count == 0)
                {
                    telemetry.SendFiltered(filter, context.ParseResult);
                }

                // If sentinel does not exist, print the welcome message showing the telemetry notification.
                if (!firstTimeUseNoticeSentinel.Exists() && !Telemetry.Telemetry.SkipFirstTimeExperience)
                {
                    context.Console.Out.WriteLine();
                    context.Console.Out.WriteLine(Telemetry.Telemetry.WelcomeMessage);

                    firstTimeUseNoticeSentinel.CreateIfNotExists();
                }

                await next(context);
            })
                   .Build());

            RootCommand DotnetInteractive()
            {
                var command = new RootCommand
                {
                    Name        = "dotnet-interactive",
                    Description = "Interactive programming for .NET."
                };

                command.AddOption(logPathOption);
                command.AddOption(verboseOption);
                command.AddOption(httpPortOption);

                return(command);
            }

            Command Jupyter()
            {
                var jupyterCommand = new Command("jupyter", "Starts dotnet-interactive as a Jupyter kernel")
                {
                    defaultKernelOption,
                    logPathOption,
                    verboseOption,
                    httpPortOption,
                    httpPortRangeOption,
                    new Argument <FileInfo>
                    {
                        Name = "connection-file"
                    }.ExistingOnly()
                };

                jupyterCommand.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>(JupyterHandler);

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter")
                {
                    logPathOption,
                    verboseOption,
                    httpPortRangeOption,
                    pathOption
                };

                installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext, PortRange, DirectoryInfo>(InstallHandler);

                jupyterCommand.AddCommand(installCommand);

                return(jupyterCommand);

                Task <int> JupyterHandler(StartupOptions startupOptions, JupyterOptions options, IConsole console, InvocationContext context)
                {
                    services.AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile))
                    .AddSingleton(_ =>
                    {
                        var frontendEnvironment = new BrowserFrontendEnvironment
                        {
                            ApiUri = new Uri($"http://localhost:{startupOptions.HttpPort}")
                        };
                        return(frontendEnvironment);
                    })
                    .AddSingleton <FrontendEnvironment>(c => c.GetService <BrowserFrontendEnvironment>())
                    .AddSingleton(c =>
                    {
                        return(CommandScheduler.Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >()
                                                                               .Trace()
                                                                               .Handle(delivery)));
                    })
                    .AddSingleton(c =>
                    {
                        var frontendEnvironment = c.GetRequiredService <BrowserFrontendEnvironment>();

                        var kernel = CreateKernel(options.DefaultKernel,
                                                  frontendEnvironment,
                                                  startupOptions,
                                                  c.GetRequiredService <HttpProbingSettings>());
                        return(kernel);
                    })
                    .AddSingleton(c => new JupyterRequestContextHandler(
                                      c.GetRequiredService <IKernel>())
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>()
                    ;

                    return(jupyter(startupOptions, console, startServer, context));
                }

                Task <int> InstallHandler(IConsole console, InvocationContext context, PortRange httpPortRange, DirectoryInfo location) =>
                new JupyterInstallCommand(console, jupyterKernelSpecInstaller: new JupyterKernelSpecInstaller(console), httpPortRange, location).InvokeAsync();
            }

            Command HttpServer()
            {
                var startKernelHttpCommand = new Command("http", "Starts dotnet-interactive with kernel functionality exposed over http")
                {
                    defaultKernelOption,
                    httpPortOption,
                    logPathOption,
                    httpPortRangeOption
                };

                startKernelHttpCommand.Handler = CommandHandler.Create <StartupOptions, KernelHttpOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    var frontendEnvironment = new BrowserFrontendEnvironment();
                    services
                    .AddSingleton(_ => frontendEnvironment)
                    .AddSingleton(c => CreateKernel(options.DefaultKernel, frontendEnvironment, startupOptions, null));

                    return(jupyter(startupOptions, console, startServer, context));
                });

                return(startKernelHttpCommand);
            }

            Command KernelServer()
            {
                var startKernelServerCommand = new Command(
                    "stdio",
                    "Starts dotnet-interactive with kernel functionality exposed over standard I/O")
                {
                    defaultKernelOption,
                    logPathOption,
                };

                startKernelServerCommand.Handler = CommandHandler.Create <StartupOptions, KernelServerOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) => startKernelServer(
                        startupOptions,
                        CreateKernel(options.DefaultKernel,
                                     new BrowserFrontendEnvironment(), startupOptions, null), console));

                return(startKernelServerCommand);
            }
        }