From a36a957392c4dd1b23319df5ca29ebaccfdabd07 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Wed, 3 Sep 2025 18:22:58 -0500 Subject: [PATCH 1/8] Make a README for the core package --- src/System.CommandLine/README.md | 227 ++++++++++++++++++ .../System.CommandLine.csproj | 2 + 2 files changed, 229 insertions(+) create mode 100644 src/System.CommandLine/README.md diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md new file mode 100644 index 0000000000..f5d6bcd941 --- /dev/null +++ b/src/System.CommandLine/README.md @@ -0,0 +1,227 @@ +# System.CommandLine + +System.CommandLine provides robust support for command-line parsing, invocation, and shell completions in .NET applications. It supports both POSIX and Windows conventions, making it easy to build professional command-line interfaces. + +## Getting Started + +### Basic Command + +Here's a simple "Hello World" command-line application: + +```csharp +using System.CommandLine; + +var rootCommand = new RootCommand("Sample command-line app"); + +var nameOption = new Option( + aliases: ["--name", "-n"], + description: "Your name"); + +rootCommand.Options.Add(nameOption); + +rootCommand.SetAction(parseResult => +{ + string name = parseResult.GetValueForOption(nameOption); + Console.WriteLine($"Hello, {name ?? "World"}!"); +}); + +return await rootCommand.InvokeAsync(args); +``` + +### Commands with Arguments + +Arguments are values passed directly to commands without option names: + +```csharp +var fileArgument = new Argument( + name: "file", + description: "The file to process"); + +var processCommand = new Command("process", "Process a file"); +processCommand.Arguments.Add(fileArgument); + +processCommand.SetAction(parseResult => +{ + FileInfo file = parseResult.GetValueForArgument(fileArgument); + Console.WriteLine($"Processing {file.FullName}"); +}); + +rootCommand.Subcommands.Add(processCommand); +``` + +### Options with Default Values + +Options can have default values and validation: + +```csharp +var delayOption = new Option( + aliases: ["--delay", "-d"], + getDefaultValue: () => 1000, + description: "Delay in milliseconds"); + +delayOption.AddValidator(result => +{ + if (result.GetValueOrDefault() < 0) + { + result.ErrorMessage = "Delay must be non-negative"; + } +}); + +rootCommand.Options.Add(delayOption); +``` + +### Subcommands + +Build complex CLI applications with nested commands: + +```csharp +var rootCommand = new RootCommand("My application"); + +var configCommand = new Command("config", "Configure the application"); +var configSetCommand = new Command("set", "Set a configuration value"); +var configGetCommand = new Command("get", "Get a configuration value"); + +var keyOption = new Option("--key", "Configuration key"); +var valueOption = new Option("--value", "Configuration value"); + +configSetCommand.Options.Add(keyOption); +configSetCommand.Options.Add(valueOption); +configGetCommand.Options.Add(keyOption); + +configCommand.Subcommands.Add(configSetCommand); +configCommand.Subcommands.Add(configGetCommand); +rootCommand.Subcommands.Add(configCommand); + +// Usage: myapp config set --key "apiUrl" --value "https://api.example.com" +// Usage: myapp config get --key "apiUrl" +``` + +### Using Options in Command Handlers + +Access option values through the ParseResult: + +```csharp +var connectionOption = new Option("--connection", "Database connection string"); +var timeoutOption = new Option("--timeout", getDefaultValue: () => 30); +var verboseOption = new Option("--verbose"); + +rootCommand.Options.Add(connectionOption); +rootCommand.Options.Add(timeoutOption); +rootCommand.Options.Add(verboseOption); + +rootCommand.SetAction(parseResult => +{ + var connection = parseResult.GetValueForOption(connectionOption); + var timeout = parseResult.GetValueForOption(timeoutOption); + var verbose = parseResult.GetValueForOption(verboseOption); + + Console.WriteLine($"Connection: {connection}"); + Console.WriteLine($"Timeout: {timeout}"); + Console.WriteLine($"Verbose: {verbose}"); +}); +``` + +### Shell Completions + +Enable tab completion for your CLI: + +```csharp +// Completions are automatically available for all commands, options, and arguments +var rootCommand = new RootCommand("My app with completions"); + +var fileOption = new Option("--file", "The file to process"); +fileOption.AddCompletions((ctx) => +{ + // Custom completion logic + return new[] { "file1.txt", "file2.txt", "file3.txt" }; +}); + +rootCommand.Options.Add(fileOption); + +// Users can generate completion scripts using dotnet-suggest: +// dotnet tool install -g dotnet-suggest +// dotnet suggest script bash > ~/.bashrc +// dotnet suggest script powershell > $PROFILE +``` + +### Async Command Handlers + +Support for asynchronous operations: + +```csharp +var urlOption = new Option("--url", "The URL to fetch"); +rootCommand.Options.Add(urlOption); + +rootCommand.SetAction(async (parseResult, cancellationToken) => +{ + var url = parseResult.GetValueForOption(urlOption); + if (url != null) + { + using var client = new HttpClient(); + var response = await client.GetStringAsync(url, cancellationToken); + Console.WriteLine(response); + } +}); + +// Or return an exit code: +rootCommand.SetAction(async (parseResult, cancellationToken) => +{ + // Your async logic here + return await Task.FromResult(0); // Return exit code +}); +``` + +## Notable Changes Since v2.0.0-beta7 + +### New Features +- **Finnish Localization**: Added Finnish language translations for help text and error messages ([#2605](https://github.com/dotnet/command-line-api/pull/2605)) +- **Improved Help System**: Enhanced `HelpAction` to allow users to provide custom `MaxWidth` for help text formatting ([#2635](https://github.com/dotnet/command-line-api/pull/2635)) +- **Task Support**: Added `SetAction` overload for `Task` return types ([#2634](https://github.com/dotnet/command-line-api/issues/2634)) +- **Implicit Arguments**: Added `ArgumentResult.Implicit` property for better argument handling ([#2622](https://github.com/dotnet/command-line-api/issues/2622), [#2625](https://github.com/dotnet/command-line-api/pull/2625)) +- **Performance Improvements**: Reduced reflection usage throughout the library for better performance ([#2662](https://github.com/dotnet/command-line-api/pull/2662)) + +### Bug Fixes +- Fixed issue [#2128](https://github.com/dotnet/command-line-api/issues/2128): Resolved command parsing edge cases ([#2656](https://github.com/dotnet/command-line-api/pull/2656)) +- Fixed issue [#2257](https://github.com/dotnet/command-line-api/issues/2257): Corrected argument validation behavior +- Fixed issue [#2589](https://github.com/dotnet/command-line-api/issues/2589): Improved error message clarity ([#2654](https://github.com/dotnet/command-line-api/pull/2654)) +- Fixed issue [#2591](https://github.com/dotnet/command-line-api/issues/2591): Resolved option parsing inconsistencies ([#2644](https://github.com/dotnet/command-line-api/pull/2644)) +- Fixed issue [#2622](https://github.com/dotnet/command-line-api/issues/2622): Enhanced implicit argument support ([#2625](https://github.com/dotnet/command-line-api/pull/2625)) +- Fixed issue [#2628](https://github.com/dotnet/command-line-api/issues/2628): Corrected help text formatting issues +- Fixed issue [#2634](https://github.com/dotnet/command-line-api/issues/2634): Added missing Task action support +- Fixed issue [#2640](https://github.com/dotnet/command-line-api/issues/2640): Resolved completion suggestions for nested commands ([#2646](https://github.com/dotnet/command-line-api/pull/2646)) + +### Breaking Changes +- Default value handling for `ProcessTerminationTimeout` has been re-added ([#2672](https://github.com/dotnet/command-line-api/pull/2672)) +- Some internal APIs have been refactored to reduce reflection usage ([#2662](https://github.com/dotnet/command-line-api/pull/2662)) + +### Other Improvements +- Updated to .NET 10.0 RC1 compatibility +- Enhanced parsing logic for better POSIX and Windows convention support +- Improved memory usage and performance optimizations +- Better handling of complex command hierarchies + +## Documentation + +For comprehensive documentation, tutorials, and API reference, visit: +- **[Microsoft Learn Documentation](https://learn.microsoft.com/en-us/dotnet/standard/commandline/)** - Complete guides and API reference +- **[GitHub Repository](https://github.com/dotnet/command-line-api)** - Source code, samples, and issues +- **[Sample Applications](https://github.com/dotnet/command-line-api/tree/main/samples)** - Real-world examples + +## Framework Support + +- **.NET 8.0+** - Full feature support with trimming and AOT compilation +- **.NET Standard 2.0** - Compatible with .NET Framework 4.6.1+, .NET Core 2.0+ + +## License + +This package is licensed under the [MIT License](https://opensource.org/licenses/MIT). + +## Contributing + +We welcome contributions! Please see our [Contributing Guide](https://github.com/dotnet/command-line-api/blob/main/CONTRIBUTING.md) for details. + +## Support + +- **Issues**: [GitHub Issues](https://github.com/dotnet/command-line-api/issues) +- **Discussions**: [GitHub Discussions](https://github.com/dotnet/command-line-api/discussions) +- **Chat**: [Gitter Community](https://gitter.im/dotnet/command-line-api) \ No newline at end of file diff --git a/src/System.CommandLine/System.CommandLine.csproj b/src/System.CommandLine/System.CommandLine.csproj index 09fd8f326a..1d86feebc4 100644 --- a/src/System.CommandLine/System.CommandLine.csproj +++ b/src/System.CommandLine/System.CommandLine.csproj @@ -7,6 +7,7 @@ Support for parsing command lines, supporting both POSIX and Windows conventions and shell-agnostic command line completions. true portable + README.md @@ -17,6 +18,7 @@ + From a87274c88798cd806e77149bf713158b8c916992 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Wed, 3 Sep 2025 18:57:51 -0500 Subject: [PATCH 2/8] fix API usage in the README --- src/System.CommandLine/README.md | 65 +++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index f5d6bcd941..a933fcd96d 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -13,9 +13,10 @@ using System.CommandLine; var rootCommand = new RootCommand("Sample command-line app"); -var nameOption = new Option( - aliases: ["--name", "-n"], - description: "Your name"); +var nameOption = new Option("--name", "-n") +{ + Description = "Your name" +}; rootCommand.Options.Add(nameOption); @@ -25,7 +26,7 @@ rootCommand.SetAction(parseResult => Console.WriteLine($"Hello, {name ?? "World"}!"); }); -return await rootCommand.InvokeAsync(args); +return await rootCommand.Parse(args).InvokeAsync(); ``` ### Commands with Arguments @@ -54,10 +55,11 @@ rootCommand.Subcommands.Add(processCommand); Options can have default values and validation: ```csharp -var delayOption = new Option( - aliases: ["--delay", "-d"], - getDefaultValue: () => 1000, - description: "Delay in milliseconds"); +var delayOption = new Option("--delay", "-d") +{ + Description = "Delay in milliseconds", + DefaultValueFactory = _ => 1000 +}; delayOption.AddValidator(result => { @@ -81,8 +83,14 @@ var configCommand = new Command("config", "Configure the application"); var configSetCommand = new Command("set", "Set a configuration value"); var configGetCommand = new Command("get", "Get a configuration value"); -var keyOption = new Option("--key", "Configuration key"); -var valueOption = new Option("--value", "Configuration value"); +var keyOption = new Option("--key") +{ + Description = "Configuration key" +}; +var valueOption = new Option("--value") +{ + Description = "Configuration value" +}; configSetCommand.Options.Add(keyOption); configSetCommand.Options.Add(valueOption); @@ -101,9 +109,19 @@ rootCommand.Subcommands.Add(configCommand); Access option values through the ParseResult: ```csharp -var connectionOption = new Option("--connection", "Database connection string"); -var timeoutOption = new Option("--timeout", getDefaultValue: () => 30); -var verboseOption = new Option("--verbose"); +var connectionOption = new Option("--connection") +{ + Description = "Database connection string" +}; +var timeoutOption = new Option("--timeout") +{ + Description = "Timeout in seconds", + DefaultValueFactory = _ => 30 +}; +var verboseOption = new Option("--verbose") +{ + Description = "Enable verbose output" +}; rootCommand.Options.Add(connectionOption); rootCommand.Options.Add(timeoutOption); @@ -129,19 +147,27 @@ Enable tab completion for your CLI: // Completions are automatically available for all commands, options, and arguments var rootCommand = new RootCommand("My app with completions"); -var fileOption = new Option("--file", "The file to process"); -fileOption.AddCompletions((ctx) => +var fileOption = new Option("--file") +{ + Description = "The file to process" +}; + +// Add custom completions using CompletionSources +fileOption.CompletionSources.Add(ctx => { - // Custom completion logic + // Custom completion logic - return completion suggestions return new[] { "file1.txt", "file2.txt", "file3.txt" }; }); +// Or add simple string suggestions +fileOption.CompletionSources.Add("option1", "option2", "option3"); + rootCommand.Options.Add(fileOption); // Users can generate completion scripts using dotnet-suggest: // dotnet tool install -g dotnet-suggest // dotnet suggest script bash > ~/.bashrc -// dotnet suggest script powershell > $PROFILE +// dotnet suggest script powershell >> $PROFILE ``` ### Async Command Handlers @@ -149,7 +175,10 @@ rootCommand.Options.Add(fileOption); Support for asynchronous operations: ```csharp -var urlOption = new Option("--url", "The URL to fetch"); +var urlOption = new Option("--url") +{ + Description = "The URL to fetch" +}; rootCommand.Options.Add(urlOption); rootCommand.SetAction(async (parseResult, cancellationToken) => From 9b885584164947a0be7ff17abc21b8c49d98ead0 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Wed, 10 Sep 2025 11:57:14 -0500 Subject: [PATCH 3/8] Update code samples and text based on review + feedback. --- src/System.CommandLine/README.md | 64 ++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index a933fcd96d..a4fcb3f78f 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -22,7 +22,7 @@ rootCommand.Options.Add(nameOption); rootCommand.SetAction(parseResult => { - string name = parseResult.GetValueForOption(nameOption); + string name = parseResult.GetValue(nameOption); Console.WriteLine($"Hello, {name ?? "World"}!"); }); @@ -34,19 +34,22 @@ return await rootCommand.Parse(args).InvokeAsync(); Arguments are values passed directly to commands without option names: ```csharp -var fileArgument = new Argument( - name: "file", - description: "The file to process"); +var fileArgument = new Argument("file") +{ + Description = "The file to process" +}; var processCommand = new Command("process", "Process a file"); processCommand.Arguments.Add(fileArgument); processCommand.SetAction(parseResult => { - FileInfo file = parseResult.GetValueForArgument(fileArgument); + FileInfo file = parseResult.GetValue(fileArgument); Console.WriteLine($"Processing {file.FullName}"); }); +var rootCommand = new RootCommand(); + rootCommand.Subcommands.Add(processCommand); ``` @@ -55,17 +58,19 @@ rootCommand.Subcommands.Add(processCommand); Options can have default values and validation: ```csharp +var rootCommand = new RootCommand(); + var delayOption = new Option("--delay", "-d") { Description = "Delay in milliseconds", DefaultValueFactory = _ => 1000 }; -delayOption.AddValidator(result => +delayOption.Validators.Add(result => { if (result.GetValueOrDefault() < 0) { - result.ErrorMessage = "Delay must be non-negative"; + result.AddError("Delay must be non-negative"); } }); @@ -129,9 +134,9 @@ rootCommand.Options.Add(verboseOption); rootCommand.SetAction(parseResult => { - var connection = parseResult.GetValueForOption(connectionOption); - var timeout = parseResult.GetValueForOption(timeoutOption); - var verbose = parseResult.GetValueForOption(verboseOption); + var connection = parseResult.GetValue(connectionOption); + var timeout = parseResult.GetValue(timeoutOption); + var verbose = parseResult.GetValue(verboseOption); Console.WriteLine($"Connection: {connection}"); Console.WriteLine($"Timeout: {timeout}"); @@ -154,22 +159,36 @@ var fileOption = new Option("--file") // Add custom completions using CompletionSources fileOption.CompletionSources.Add(ctx => -{ - // Custom completion logic - return completion suggestions - return new[] { "file1.txt", "file2.txt", "file3.txt" }; -}); + // hard-coded list of files + ["file1.txt", "file2.txt", "file3.txt" ] +); // Or add simple string suggestions fileOption.CompletionSources.Add("option1", "option2", "option3"); rootCommand.Options.Add(fileOption); +``` -// Users can generate completion scripts using dotnet-suggest: -// dotnet tool install -g dotnet-suggest -// dotnet suggest script bash > ~/.bashrc -// dotnet suggest script powershell >> $PROFILE +Users can then easily trigger your completions using `dotnet-suggest`: + +```shell +> dotnet tool install -g dotnet-suggest +> dotnet suggest script bash > ~/.bashrc +``` + +```powershell +> dotnet tool install -g dotnet-suggest +> dotnet suggest script powershell >> $PROFILE ``` +Once `dotnet-suggest` is installed, you can register your app with it for completions support: + +```shell +> dotnet-suggest register --command-path /path/to/myapp +``` + +Alternatively, you can create your own commands for completion generation and instruct users on how to set them up. + ### Async Command Handlers Support for asynchronous operations: @@ -183,7 +202,7 @@ rootCommand.Options.Add(urlOption); rootCommand.SetAction(async (parseResult, cancellationToken) => { - var url = parseResult.GetValueForOption(urlOption); + var url = parseResult.GetValue(urlOption); if (url != null) { using var client = new HttpClient(); @@ -204,9 +223,9 @@ rootCommand.SetAction(async (parseResult, cancellationToken) => ### New Features - **Finnish Localization**: Added Finnish language translations for help text and error messages ([#2605](https://github.com/dotnet/command-line-api/pull/2605)) -- **Improved Help System**: Enhanced `HelpAction` to allow users to provide custom `MaxWidth` for help text formatting ([#2635](https://github.com/dotnet/command-line-api/pull/2635)) -- **Task Support**: Added `SetAction` overload for `Task` return types ([#2634](https://github.com/dotnet/command-line-api/issues/2634)) -- **Implicit Arguments**: Added `ArgumentResult.Implicit` property for better argument handling ([#2622](https://github.com/dotnet/command-line-api/issues/2622), [#2625](https://github.com/dotnet/command-line-api/pull/2625)) +- **Improved Help System**: Enhanced `HelpAction` to allow users to provide custom `MaxWidth` for help text formatting ([#2635](https://github.com/dotnet/command-line-api/pull/2635)). Note that if you create custom Help or Version actions, you'll want to set `ClearsParseErrors` to `true` to ensure that invoking those features isn't treated like an error by the parser. +- **`Task` Support**: Added `SetAction` overload for `Task` return types ([#2634](https://github.com/dotnet/command-line-api/issues/2634)) +- **Detect Implicit Arguments**: Added the `ArgumentResult.Implicit` property for better argument handling ([#2622](https://github.com/dotnet/command-line-api/issues/2622), [#2625](https://github.com/dotnet/command-line-api/pull/2625)) - **Performance Improvements**: Reduced reflection usage throughout the library for better performance ([#2662](https://github.com/dotnet/command-line-api/pull/2662)) ### Bug Fixes @@ -225,7 +244,6 @@ rootCommand.SetAction(async (parseResult, cancellationToken) => ### Other Improvements - Updated to .NET 10.0 RC1 compatibility -- Enhanced parsing logic for better POSIX and Windows convention support - Improved memory usage and performance optimizations - Better handling of complex command hierarchies From 3472eda4b1692610e3abd63c6472b454e2b017cc Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Thu, 11 Sep 2025 10:18:23 -0500 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Adam Sitnik --- src/System.CommandLine/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index a4fcb3f78f..4826347c7a 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -11,9 +11,9 @@ Here's a simple "Hello World" command-line application: ```csharp using System.CommandLine; -var rootCommand = new RootCommand("Sample command-line app"); +RootCommand rootCommand = new("Sample command-line app"); -var nameOption = new Option("--name", "-n") +Option nameOption = new("--name", "-n") { Description = "Your name" }; @@ -26,7 +26,7 @@ rootCommand.SetAction(parseResult => Console.WriteLine($"Hello, {name ?? "World"}!"); }); -return await rootCommand.Parse(args).InvokeAsync(); +return rootCommand.Parse(args).Invoke(); ``` ### Commands with Arguments @@ -109,7 +109,7 @@ rootCommand.Subcommands.Add(configCommand); // Usage: myapp config get --key "apiUrl" ``` -### Using Options in Command Handlers +### Using Options in Command Actions Access option values through the ParseResult: From 7ccb27f051019cdd555eeacae5b37599f0a4f411 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Thu, 11 Sep 2025 10:22:07 -0500 Subject: [PATCH 5/8] Clarify what RootCommand does --- src/System.CommandLine/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index 4826347c7a..45ce68c93a 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -29,6 +29,14 @@ rootCommand.SetAction(parseResult => return rootCommand.Parse(args).Invoke(); ``` +In this example, we create a `RootCommand`, add an option for the user's name, and define an action that prints a greeting. The `RootCommand` is a special kind of `Command` that comes with a few predefined behaviors: + +* It discovers its name automatically from the currently-running application +* It automatically provides `--help` and `--version` options and default behaviors for them +* It provides a default integration with `dotnet-suggest` for dynamic [shell completions](#shell-completions) + +You can always override or customize these behaviors as needed on a `RootCommand`, or create your own top-level `Command` instead. + ### Commands with Arguments Arguments are values passed directly to commands without option names: From 66ba9524ad56ae12e03affbf119334a0a96a97cb Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Thu, 25 Sep 2025 15:09:24 -0500 Subject: [PATCH 6/8] remove mention of Finnish translation as it's not yet in the package --- src/System.CommandLine/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index 45ce68c93a..83b870c93f 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -230,7 +230,6 @@ rootCommand.SetAction(async (parseResult, cancellationToken) => ## Notable Changes Since v2.0.0-beta7 ### New Features -- **Finnish Localization**: Added Finnish language translations for help text and error messages ([#2605](https://github.com/dotnet/command-line-api/pull/2605)) - **Improved Help System**: Enhanced `HelpAction` to allow users to provide custom `MaxWidth` for help text formatting ([#2635](https://github.com/dotnet/command-line-api/pull/2635)). Note that if you create custom Help or Version actions, you'll want to set `ClearsParseErrors` to `true` to ensure that invoking those features isn't treated like an error by the parser. - **`Task` Support**: Added `SetAction` overload for `Task` return types ([#2634](https://github.com/dotnet/command-line-api/issues/2634)) - **Detect Implicit Arguments**: Added the `ArgumentResult.Implicit` property for better argument handling ([#2622](https://github.com/dotnet/command-line-api/issues/2622), [#2625](https://github.com/dotnet/command-line-api/pull/2625)) From f03fc0c1b8615642220fe567bbbbec552c0241ca Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Thu, 25 Sep 2025 15:10:19 -0500 Subject: [PATCH 7/8] remove mention of gitter --- src/System.CommandLine/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index 83b870c93f..51341c0a65 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -277,5 +277,4 @@ We welcome contributions! Please see our [Contributing Guide](https://github.com ## Support - **Issues**: [GitHub Issues](https://github.com/dotnet/command-line-api/issues) -- **Discussions**: [GitHub Discussions](https://github.com/dotnet/command-line-api/discussions) -- **Chat**: [Gitter Community](https://gitter.im/dotnet/command-line-api) \ No newline at end of file +- **Discussions**: [GitHub Discussions](https://github.com/dotnet/command-line-api/discussions) \ No newline at end of file From 4e0ad95ed94307c9b15d1507ba8e8849619106a8 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Thu, 25 Sep 2025 15:11:52 -0500 Subject: [PATCH 8/8] remove dead link --- src/System.CommandLine/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.CommandLine/README.md b/src/System.CommandLine/README.md index 51341c0a65..da48b892a3 100644 --- a/src/System.CommandLine/README.md +++ b/src/System.CommandLine/README.md @@ -259,7 +259,6 @@ rootCommand.SetAction(async (parseResult, cancellationToken) => For comprehensive documentation, tutorials, and API reference, visit: - **[Microsoft Learn Documentation](https://learn.microsoft.com/en-us/dotnet/standard/commandline/)** - Complete guides and API reference - **[GitHub Repository](https://github.com/dotnet/command-line-api)** - Source code, samples, and issues -- **[Sample Applications](https://github.com/dotnet/command-line-api/tree/main/samples)** - Real-world examples ## Framework Support