Repository: dotnet/sdk
Pull request #47873: `dotnet package list` command should restore first
Author: login: Nigusu-Allehu
Labels: name: Area-Infrastructure
name: untriaged
description: Request triage from a team member
name: breaking-change
description: Using this label will notify dotnet/compat and trigger a request to file a compat bug
Created: 2025-03-25T16:56:50Z | Merged: 2025-04-09T15:15:02Z

https://github.com/dotnet/sdk/pull/47400 had to many conflicts. 
Fixes: https://github.com/NuGet/Home/issues/13406

## Description

This PR
* Adds implicit restore to `dotnet package list` command or `dotnet list package` (https://github.com/dotnet/sdk/pull/45384)

### ScreenShots
* `package list --project [project]`
![image](https://github.com/user-attachments/assets/62b8544a-cd97-4455-81de-c261725c9822)
* --format json
![image](https://github.com/user-attachments/assets/9bb19b7a-6ef7-4585-9c4f-0d0d88f4d7eb)
* restore error
![image](https://github.com/user-attachments/assets/2c8a1321-0815-4c75-b15d-342d77d84522)

* restore error: --format json
![image](https://github.com/user-attachments/assets/8701db75-e5ac-41e9-aaf3-6a3ff4d6ad04)





Diff:
diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx
index d18c552b8f74..7c44013e6890 100644
--- a/src/Cli/dotnet/Commands/CliCommandStrings.resx
+++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx
@@ -483,6 +483,13 @@ This is equivalent to deleting project.assets.json.</value>
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
+    <comment>{Locked="dotnet restore"}</comment>
+  </data>
+  <data name="CmdNoRestoreDescription" xml:space="preserve">
+    <value>Do not restore before running the command.</value>
+  </data>
   <data name="CmdPackage" xml:space="preserve">
     <value>PACKAGE_NAME</value>
   </data>
diff --git a/src/Cli/dotnet/Commands/Hidden/List/Package/ListPackageCommandParser.cs b/src/Cli/dotnet/Commands/Hidden/List/Package/ListPackageCommandParser.cs
index faa7cc354274..c491827a12cd 100644
--- a/src/Cli/dotnet/Commands/Hidden/List/Package/ListPackageCommandParser.cs
+++ b/src/Cli/dotnet/Commands/Hidden/List/Package/ListPackageCommandParser.cs
@@ -33,6 +33,7 @@ private static CliCommand ConstructCommand()
         command.Options.Add(PackageListCommandParser.InteractiveOption);
         command.Options.Add(PackageListCommandParser.FormatOption);
         command.Options.Add(PackageListCommandParser.OutputVersionOption);
+        command.Options.Add(PackageListCommandParser.NoRestore);
 
         command.SetAction((parseResult) => new PackageListCommand(parseResult).Execute());
 
diff --git a/src/Cli/dotnet/Commands/Package/List/PackageListCommand.cs b/src/Cli/dotnet/Commands/Package/List/PackageListCommand.cs
index 3f8dae9aee19..04bbeffc7493 100644
--- a/src/Cli/dotnet/Commands/Package/List/PackageListCommand.cs
+++ b/src/Cli/dotnet/Commands/Package/List/PackageListCommand.cs
@@ -6,6 +6,8 @@
 using Microsoft.DotNet.Cli.Commands.NuGet;
 using Microsoft.DotNet.Cli.Extensions;
 using Microsoft.DotNet.Cli.Utils;
+using System.Globalization;
+using Microsoft.DotNet.Cli.Commands.MSBuild;
 
 namespace Microsoft.DotNet.Cli.Commands.Package.List;
 
@@ -25,7 +27,71 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        args.Add($"-interactive:{interactive.ToString().ToLower()}");
+
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
+   "problems": [
+      {
+         "text": "{{String.Format(CultureInfo.CurrentCulture, CliCommandStrings.Error_restore)}}",
+         "level": "error"
+      }
+   ]
+}
+""";
+                Console.WriteLine(jsonError);
+            }
+        }
+
+        return exitCode;
     }
 
     internal static void EnforceOptionRules(ParseResult parseResult)
@@ -40,13 +106,13 @@ internal static void EnforceOptionRules(ParseResult parseResult)
         }
     }
 
-    private string[] TransformArgs()
+    private string[] TransformArgs(string projectOrSolution)
     {
         var args = new List<string>
         {
             "package",
             "list",
-            GetProjectOrSolution()
+            projectOrSolution
         };
 
         args.AddRange(_parseResult.OptionValuesToBeForwarded(PackageListCommandParser.GetCommand()));
diff --git a/src/Cli/dotnet/Commands/Package/List/PackageListCommandParser.cs b/src/Cli/dotnet/Commands/Package/List/PackageListCommandParser.cs
index 6aaa53d79641..88904d6de15a 100644
--- a/src/Cli/dotnet/Commands/Package/List/PackageListCommandParser.cs
+++ b/src/Cli/dotnet/Commands/Package/List/PackageListCommandParser.cs
@@ -72,6 +72,12 @@ internal static class PackageListCommandParser
 
     public static readonly CliOption InteractiveOption = CommonOptions.InteractiveOption().ForwardIfEnabled("--interactive");
 
+    public static readonly CliOption NoRestore = new CliOption<bool>("--no-restore")
+    {
+        Description = CliCommandStrings.CmdNoRestoreDescription,
+        Arity = ArgumentArity.Zero
+    };
+
     public static readonly CliOption VerbosityOption = new ForwardedOption<VerbosityOptions>("--verbosity", "-v")
     {
         Description = CliStrings.VerbosityOptionDescription,
@@ -113,6 +119,7 @@ private static CliCommand ConstructCommand()
         command.Options.Add(InteractiveOption);
         command.Options.Add(FormatOption);
         command.Options.Add(OutputVersionOption);
+        command.Options.Add(NoRestore);
         command.Options.Add(PackageCommandParser.ProjectOption);
 
         command.SetAction((parseResult) => new PackageListCommand(parseResult).Execute());
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
index b40213fe208b..28c05970ec5d 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
index 084d78a04136..6934ad07dc21 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
index b52aee8f86dc..986040944a9a 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
index 15a358999121..699e27cf1172 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
index 89c2748bdcb5..2e5547ff20df 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
index 101a5ec62e38..195f49f4dbf7 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
index f9ae5c299e5b..ada8d1ee5139 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
index 33642773ddff..d6df366369c5 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
index 5e076eb7a4f4..d90cb2c746d3 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
index 79dee0e34032..5105335f3ce0 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
index b88fbaf94bbe..b4cf621b2847 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
index d5a469a80b1a..bf305c614a41 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
index a8ac9272ab9d..97dc514087ec 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
@@ -561,6 +561,11 @@ This is equivalent to deleting project.assets.json.</target>
         <target state="new">Specify a project or solution file. The current working directory does not contain a project or solution file.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CmdNoRestoreDescription">
+        <source>Do not restore before running the command.</source>
+        <target state="new">Do not restore before running the command.</target>
+        <note />
+      </trans-unit>
       <trans-unit id="CmdNoTestModulesErrorDescription">
         <source>No test modules found for the given test module pattern: {0} with root directory: {1}</source>
         <target state="new">No test modules found for the given test module pattern: {0} with root directory: {1}</target>
@@ -1061,6 +1066,11 @@ Make the profile names distinct.</source>
 Make the profile names distinct.</target>
         <note />
       </trans-unit>
+      <trans-unit id="Error_restore">
+        <source>Restore failed. Run `dotnet restore` for more details on the issue.</source>
+        <target state="new">Restore failed. Run `dotnet restore` for more details on the issue.</target>
+        <note>{Locked="dotnet restore"}</note>
+      </trans-unit>
       <trans-unit id="ExactMatchDescription">
         <source>Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</source>
         <target state="new">Require that the search term exactly match the name of the package. Causes `--take` and `--skip` options to be ignored.</target>
diff --git a/test/Microsoft.NET.TestFramework/Commands/PackageListCommand.cs b/test/Microsoft.NET.TestFramework/Commands/PackageListCommand.cs
new file mode 100644
index 000000000000..b99407ed4072
--- /dev/null
+++ b/test/Microsoft.NET.TestFramework/Commands/PackageListCommand.cs
@@ -0,0 +1,35 @@
+﻿// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.DotNet.Cli.Utils;
+
+namespace Microsoft.NET.TestFramework.Commands
+{
+    public class PackageListCommand : DotnetCommand
+    {
+        private string? _projectName = null;
+
+        public PackageListCommand(ITestOutputHelper log, params string[] args) : base(log, args)
+        {
+        }
+
+        public override CommandResult Execute(IEnumerable<string> args)
+        {
+            List<string> newArgs = ["package", "list"];
+            if (!string.IsNullOrEmpty(_projectName))
+            {
+                newArgs.Add("--project");
+                newArgs.Add(_projectName);
+            }
+            newArgs.AddRange(args);
+
+            return base.Execute(newArgs);
+        }
+
+        public PackageListCommand WithProject(string projectName)
+        {
+            _projectName = projectName;
+            return this;
+        }
+    }
+}
diff --git a/test/dotnet-completions.Tests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet-completions.Tests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh
index 9a4a003fe1d0..44dc106b1abb 100644
--- a/test/dotnet-completions.Tests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh
+++ b/test/dotnet-completions.Tests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh
@@ -1083,7 +1083,7 @@ _testhost_package_list() {
     prev="${COMP_WORDS[COMP_CWORD-1]}" 
     COMPREPLY=()
     
-    opts="--verbosity --outdated --deprecated --vulnerable --framework --include-transitive --include-prerelease --highest-patch --highest-minor --config --source --interactive --format --output-version --project --help" 
+    opts="--verbosity --outdated --deprecated --vulnerable --framework --include-transitive --include-prerelease --highest-patch --highest-minor --config --source --interactive --format --output-version --no-restore --project --help" 
     
     if [[ $COMP_CWORD == "$1" ]]; then
         COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
@@ -2224,4 +2224,4 @@ _testhost_completions_script() {
 
 
 
-complete -F _testhost testhost
\ No newline at end of file
+complete -F _testhost testhost
diff --git a/test/dotnet-completions.Tests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet-completions.Tests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1
index b8ba20263713..5433aad3fe93 100644
--- a/test/dotnet-completions.Tests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1
+++ b/test/dotnet-completions.Tests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1
@@ -636,6 +636,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock {
                 [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).")
                 [CompletionResult]::new('--format', '--format', [CompletionResultType]::ParameterName, "Specifies the output format type for the list packages command.")
                 [CompletionResult]::new('--output-version', '--output-version', [CompletionResultType]::ParameterName, "Specifies the version of machine-readable output. Requires the `'--format json`' option.")
+                [CompletionResult]::new('--no-restore', '--no-restore', [CompletionResultType]::ParameterName, "Do not restore before running the command.")
                 [CompletionResult]::new('--project', '--project', [CompletionResultType]::ParameterName, "The project file to operate on. If a file is not specified, the command will search the current directory for one.")
                 [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.")
                 [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.")
diff --git a/test/dotnet-completions.Tests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet-completions.Tests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh
index 451a9b00d108..5795644bd951 100644
--- a/test/dotnet-completions.Tests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh
+++ b/test/dotnet-completions.Tests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh
@@ -629,6 +629,7 @@ _testhost() {
                                             '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \
                                             '--format=[Specifies the output format type for the list packages command.]: :((console\:"console" json\:"json" ))' \
                                             '--output-version=[Specifies the version of machine-readable output. Requires the '\''--format json'\'' option.]: : ' \
+                                            '--no-restore[Do not restore before running the command.]' \
                                             '--project=[The project file to operate on. If a file is not specified, the command will search the current directory for one.]: : ' \
                                             '--help[Show command line help.]' \
                                             '-h[Show command line help.]' \
diff --git a/test/dotnet-list-package.Tests/GivenDotnetListPackage.cs b/test/dotnet-list-package.Tests/GivenDotnetListPackage.cs
index 4e0be90d99ca..bef15fa249b4 100644
--- a/test/dotnet-list-package.Tests/GivenDotnetListPackage.cs
+++ b/test/dotnet-list-package.Tests/GivenDotnetListPackage.cs
@@ -139,12 +139,30 @@ public void AssetsPathExistsButNotRestored()
 
             new ListPackageCommand(Log)
                 .WithWorkingDirectory(projectDirectory)
-                .Execute()
+                .Execute("--no-restore")
                 .Should()
                 .Fail()
                 .And.HaveStdErr();
         }
 
+        [Fact]
+        public void RestoresAndLists()
+        {
+            var testAsset = "NewtonSoftDependentProject";
+            var projectDirectory = _testAssetsManager
+                .CopyTestAsset(testAsset)
+                .WithSource()
+                .Path;
+
+            new ListPackageCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.HaveStdOut()
+                .And.HaveStdOutContaining("NewtonSoft.Json");
+        }
+
         [Fact]
         public void ItListsTransitivePackage()
         {
@@ -325,7 +343,7 @@ public void ItListsFSharpProject()
         public void ItEnforcesOptionRules(bool throws, params string[] options)
         {
             var parseResult = Parser.Instance.Parse($"dotnet list package {string.Join(' ', options)}");
-            Action checkRules = () => PackageListCommand.EnforceOptionRules(parseResult);
+            Action checkRules = () => Microsoft.DotNet.Cli.Commands.Package.List.PackageListCommand.EnforceOptionRules(parseResult);
 
             if (throws)
             {
diff --git a/test/dotnet-pacakge-list/GivenDotnetPackageList.cs b/test/dotnet-pacakge-list/GivenDotnetPackageList.cs
new file mode 100644
index 000000000000..54c06652ec0f
--- /dev/null
+++ b/test/dotnet-pacakge-list/GivenDotnetPackageList.cs
@@ -0,0 +1,460 @@
+﻿// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#nullable disable
+
+using Microsoft.DotNet.Cli.Utils;
+using Microsoft.DotNet.Tools.Package.List;
+
+namespace Microsoft.DotNet.Cli.Commands.Package.List.Tests
+{
+    public class GivenDotnetPackageList : SdkTest
+    {
+        public GivenDotnetPackageList(ITestOutputHelper output) : base(output)
+        {
+        }
+
+        [Fact]
+        public void ItShowsCoreOutputOnMinimalVerbosity()
+        {
+            var testAssetName = "NewtonSoftDependentProject";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName)
+                .WithSource();
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--verbosity", "quiet", "--no-restore")
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr()
+                .And.HaveStdOutContaining("NewtonSoft.Json");
+        }
+
+        [Fact]
+        public void RequestedAndResolvedVersionsMatch()
+        {
+            var testAssetName = "TestAppSimple";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName)
+                .WithSource();
+
+            var projectDirectory = testAsset.Path;
+
+            var packageName = "Newtonsoft.Json";
+            var packageVersion = ToolsetInfo.GetNewtonsoftJsonPackageVersion();
+            var cmd = new DotnetCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("add", "package", packageName, "--version", packageVersion);
+            cmd.Should().Pass();
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--no-restore")
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr()
+                .And.HaveStdOutContainingIgnoreSpaces(packageName + packageVersion + packageVersion);
+        }
+
+        [Fact]
+        public void ItListsAutoReferencedPackages()
+        {
+            var testAssetName = "TestAppSimple";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName)
+                .WithSource()
+                .WithProjectChanges(ChangeTargetFrameworkTo2_1);
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--no-restore")
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr()
+                .And.HaveStdOutContainingIgnoreSpaces("Microsoft.NETCore.App(A)")
+                .And.HaveStdOutContainingIgnoreSpaces("(A):Auto-referencedpackage");
+
+            static void ChangeTargetFrameworkTo2_1(XDocument project)
+            {
+                project.Descendants()
+                       .Single(e => e.Name.LocalName == "TargetFramework")
+                       .Value = "netcoreapp2.1";
+            }
+        }
+
+        [Fact]
+        public void ItRunOnSolution()
+        {
+            var sln = "TestAppWithSlnAndSolutionFolders";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(sln)
+                .WithSource();
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset, "App.sln")
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            new PackageListCommand(Log)
+                .WithProject("App.sln")
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--no-restore")
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr()
+                .And.HaveStdOutContainingIgnoreSpaces("NewtonSoft.Json");
+        }
+
+        [Fact]
+        public void AssetsPathExistsButNotRestored()
+        {
+            var testAsset = "NewtonSoftDependentProject";
+            var projectDirectory = _testAssetsManager
+                .CopyTestAsset(testAsset)
+                .WithSource()
+                .Path;
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--no-restore")
+                .Should()
+                .Fail()
+                .And.HaveStdErr();
+        }
+
+
+        [Fact]
+        public void RestoresAndLists()
+        {
+            var testAsset = "NewtonSoftDependentProject";
+            var projectDirectory = _testAssetsManager
+                .CopyTestAsset(testAsset)
+                .WithSource()
+                .Path;
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.HaveStdOut()
+                .And.HaveStdOutContaining("NewtonSoft.Json");
+        }
+
+        [Fact]
+        public void ItListsTransitivePackage()
+        {
+            var testProject = new TestProject
+            {
+                Name = "NewtonSoftDependentProject",
+                TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+                IsExe = true,
+                SourceFiles =
+                {
+["Program.cs"] = @"
+using System;
+using System.Collections;
+using Newtonsoft.Json.Linq;
+
+class Program
+{
+    public static void Main(string[] args)
+    {
+        ArrayList argList = new ArrayList(args);
+        JObject jObject = new JObject();
+
+        foreach (string arg in argList)
+        {
+            jObject[arg] = arg;
+        }
+        Console.WriteLine(jObject.ToString());
+    }
+}
+",
+                }
+            };
+
+            testProject.PackageReferences.Add(new TestPackageReference("NewtonSoft.Json", "9.0.1"));
+
+            //  Disable package pruning so that there are still transitive dependencies to test the command
+            testProject.AdditionalProperties["RestoreEnablePackagePruning"] = "false";
+
+            var testAsset = _testAssetsManager.CreateTestProject(testProject);
+            var projectDirectory = Path.Combine(testAsset.Path, testProject.Name);
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--no-restore")
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr()
+                .And.NotHaveStdOutContaining("System.IO.FileSystem");
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute(args: ["--include-transitive", "--no-restore"])
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr()
+                .And.HaveStdOutContaining("System.IO.FileSystem");
+        }
+
+        [Theory]
+        [InlineData("", "[net451]", null)]
+        [InlineData("", $"[{ToolsetInfo.CurrentTargetFramework}]", null)]
+        [InlineData($"--framework {ToolsetInfo.CurrentTargetFramework} --framework net451", "[net451]", null)]
+        [InlineData($"--framework {ToolsetInfo.CurrentTargetFramework} --framework net451", $"[{ToolsetInfo.CurrentTargetFramework}]", null)]
+        [InlineData($"--framework {ToolsetInfo.CurrentTargetFramework}", $"[{ToolsetInfo.CurrentTargetFramework}]", "[net451]")]
+        [InlineData("--framework net451", "[net451]", "[netcoreapp3.0]")]
+        [InlineData($"-f {ToolsetInfo.CurrentTargetFramework} -f net451", "[net451]", null)]
+        [InlineData($"-f {ToolsetInfo.CurrentTargetFramework} -f net451", $"[{ToolsetInfo.CurrentTargetFramework}]", null)]
+        [InlineData($"-f {ToolsetInfo.CurrentTargetFramework}", $"[{ToolsetInfo.CurrentTargetFramework}]", "[net451]")]
+        [InlineData("-f net451", "[net451]", "[netcoreapp3.0]")]
+        public void ItListsValidFrameworks(string args, string shouldInclude, string shouldntInclude)
+        {
+            var testAssetName = "MSBuildAppWithMultipleFrameworks";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName, identifier: args.GetHashCode().ToString() + shouldInclude)
+                .WithSource();
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            if (shouldntInclude == null)
+            {
+                new PackageListCommand(Log)
+                    .WithWorkingDirectory(projectDirectory)
+                    .Execute(args.Split(' ', options: StringSplitOptions.RemoveEmptyEntries))
+                    .Should()
+                    .Pass()
+                    .And.NotHaveStdErr()
+                    .And.HaveStdOutContainingIgnoreSpaces(shouldInclude.Replace(" ", ""));
+            }
+            else
+            {
+                new PackageListCommand(Log)
+                    .WithWorkingDirectory(projectDirectory)
+                    .Execute(args.Split(' ', options: StringSplitOptions.RemoveEmptyEntries))
+                    .Should()
+                    .Pass()
+                    .And.NotHaveStdErr()
+                    .And.HaveStdOutContainingIgnoreSpaces(shouldInclude.Replace(" ", ""))
+                    .And.NotHaveStdOutContaining(shouldntInclude.Replace(" ", ""));
+            }
+
+        }
+
+        [Fact]
+        public void ItDoesNotAcceptInvalidFramework()
+        {
+            var testAssetName = "MSBuildAppWithMultipleFrameworks";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName)
+                .WithSource();
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute("--framework", "invalid")
+                .Should()
+                .Fail();
+        }
+
+        [FullMSBuildOnlyFact]
+        public void ItListsFSharpProject()
+        {
+            var testAssetName = "FSharpTestAppSimple";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName)
+                .WithSource();
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute()
+                .Should()
+                .Pass()
+                .And.NotHaveStdErr();
+        }
+
+        [Theory]
+        [InlineData(false, "--no-restore")]
+        [InlineData(false, "--vulnerable")]
+        [InlineData(false, "--no-restore", "--include-transitive")]
+        [InlineData(false, "--no-restore", "--include-prerelease")]
+        [InlineData(false, "--no-restore", "--deprecated")]
+        [InlineData(false, "--no-restore", "--outdated")]
+        [InlineData(false, "--no-restore", "--vulnerable")]
+        [InlineData(false, "--vulnerable", "--include-transitive")]
+        [InlineData(false, "--vulnerable", "--include-prerelease")]
+        [InlineData(false, "--deprecated", "--highest-minor")]
+        [InlineData(false, "--deprecated", "--highest-patch")]
+        [InlineData(false, "--outdated", "--include-prerelease")]
+        [InlineData(false, "--outdated", "--highest-minor")]
+        [InlineData(false, "--outdated", "--highest-patch")]
+        [InlineData(false, "--config")]
+        [InlineData(false, "--configfile")]
+        [InlineData(false, "--source")]
+        [InlineData(false, "-s")]
+        [InlineData(false, "--config", "--deprecated")]
+        [InlineData(false, "--configfile", "--deprecated")]
+        [InlineData(false, "--source", "--vulnerable")]
+        [InlineData(false, "-s", "--vulnerable")]
+        [InlineData(true, "--vulnerable", "--deprecated")]
+        [InlineData(true, "--vulnerable", "--outdated")]
+        [InlineData(true, "--deprecated", "--outdated")]
+        public void ItEnforcesOptionRules(bool throws, params string[] options)
+        {
+            var parseResult = Parser.Instance.Parse($"dotnet package list {string.Join(' ', options)}");
+            Action checkRules = () => ListPackageReferencesCommand.EnforceOptionRules(parseResult);
+
+            if (throws)
+            {
+                Assert.Throws<GracefulException>(checkRules);
+            }
+            else
+            {
+                checkRules(); // Test for no throw
+            }
+        }
+
+        [UnixOnlyFact]
+        public void ItRunsInCurrentDirectoryWithPoundInPath()
+        {
+            // Regression test for https://github.com/dotnet/sdk/issues/19654
+            var testAssetName = "TestAppSimple";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName, "C#")
+                .WithSource();
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass();
+
+            new PackageListCommand(Log)
+                .WithWorkingDirectory(projectDirectory)
+                .Execute()
+                .Should()
+                .Pass();
+        }
+
+        [Fact]
+        public void ItRecognizesRelativePathsForAProject()
+        {
+            var testAssetName = "TestAppSimple";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(testAssetName)
+                .WithSource();
+
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset)
+                .Execute()
+                .Should()
+                .Pass();
+
+            new PackageListCommand(Log)
+                .WithProject("TestAppSimple.csproj")
+                .WithWorkingDirectory(projectDirectory)
+                .Execute()
+                .Should()
+                .Pass();
+        }
+
+        [Fact]
+        public void ItRecognizesRelativePathsForASolution()
+        {
+            var sln = "TestAppWithSlnAndSolutionFolders";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(sln)
+                .WithSource();
+
+            var projectDirectory = testAsset.Path;
+
+            new RestoreCommand(testAsset, "App.sln")
+                .Execute()
+                .Should()
+                .Pass();
+
+            new PackageListCommand(Log)
+                .WithProject("App.sln")
+                .WithWorkingDirectory(projectDirectory)
+                .Execute()
+                .Should()
+                .Pass();
+        }
+
+        [Fact]
+        public void ItRecognizesRelativePathsForASolutionFromSubFolder()
+        {
+            var sln = "TestAppWithSlnAndSolutionFolders";
+            var testAsset = _testAssetsManager
+                .CopyTestAsset(sln)
+                .WithSource();
+
+            var projectDirectory = testAsset.Path;
+
+            string subFolderName = "subFolder";
+            var subFolderPath = Path.Combine(projectDirectory, subFolderName);
+            Directory.CreateDirectory(subFolderPath);
+
+            new RestoreCommand(testAsset, "App.sln")
+                .Execute()
+                .Should()
+                .Pass();
+
+            new PackageListCommand(Log)
+                .WithProject("../App.sln")
+                .WithWorkingDirectory(subFolderPath)
+                .Execute()
+                .Should()
+                .Pass();
+        }
+    }
+}
diff --git a/test/dotnet.Tests/dotnet.Tests.csproj b/test/dotnet.Tests/dotnet.Tests.csproj
index b242b6f20c07..00427dd42924 100644
--- a/test/dotnet.Tests/dotnet.Tests.csproj
+++ b/test/dotnet.Tests/dotnet.Tests.csproj
@@ -39,6 +39,7 @@
     <Compile Include="..\dotnet-list-reference.Tests\**\*.cs" LinkBase="dotnet-list-reference" />
     <Compile Include="..\dotnet-nuget.UnitTests\**\*.cs" LinkBase="dotnet-nuget" />
     <Compile Include="..\dotnet-pack.Tests\**\*.cs" LinkBase="dotnet-pack" />
+    <Compile Include="..\dotnet-package-list.Tests\**\*.cs" LinkBase="dotnet-package-list" />
     <Compile Include="..\dotnet-project-convert.Tests\**\*.cs" LinkBase="dotnet-project-convert" />
     <Compile Include="..\dotnet-publish.Tests\**\*.cs" LinkBase="dotnet-publish" />
     <Compile Include="..\dotnet-remove-package.Tests\**\*.cs" LinkBase="dotnet-remove-package" />


Reviews:
user: login: zivkan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T20:16:50Z
user: login: jeffkl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:18:10Z
user: login: baronfel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T17:29:26Z
user: login: jeffkl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T18:05:01Z
user: login: Forgind
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:35:30Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T19:51:44Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T19:52:24Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T20:06:41Z
user: login: zivkan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T22:26:28Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T23:02:32Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T23:14:45Z
user: login: Forgind
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T02:09:24Z
user: login: jebriede
state: APPROVED
author_association: NONE
submitted_at: 2025-04-08T17:50:27Z
user: login: aortiz-msft
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T18:05:46Z
user: login: Forgind
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T19:28:34Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T23:42:44Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T23:48:30Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T23:49:45Z
user: login: aortiz-msft
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T23:54:53Z
user: login: Forgind
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T00:02:21Z
user: login: zivkan
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T05:43:18Z
user: login: Nigusu-Allehu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T15:23:34Z

Review comments:
diff_hunk: @@ -30,7 +32,59 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            restoreExitCode = RunRestore(projectFile, formatOption);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption)
+    {
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: ["-target:restore", projectOrSolution, "-noConsoleLogger"]);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError =
+    "{\r\n" +
+    "   \"version\": 1,\r\n" +
+    "   \"problems\": [\r\n" +
+    "      {\r\n" +
+    $"         \"text\": \"{String.Format(CultureInfo.CurrentCulture, LocalizableStrings.Error_restore)}\",\r\n" +
+    "         \"level\": \"error\"\r\n" +
+    "      }\r\n" +
+    "   ]\r\n" +
path: src/Cli/dotnet/commands/Package/list/ListPackageReferencesCommand.cs
user: login: zivkan
body: Line endings are different on Windows and Linux (and in the past Mac too, but I can't remember if Mac is the same as Linux now, or still different to both).  Plus on Windows I'm not sure if `Console.WriteLine` (well, technically `StringWriter`) detects `\n` and converts it to `\r\n`, so maybe there's risk that explicitly putting in `\r\n` will cause the output to contain `\r\r\n`.

Anyway, I'd suggest using [raw string literals](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string) and assume that the compiler is going to do the right thing
created_at: 2025-03-25T20:16:49Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,60 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            restoreExitCode = RunRestore(projectFile, formatOption);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption)
+    {
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: ["-target:restore", projectOrSolution, "-noConsoleLogger"]);
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: jeffkl
body: Since the implicit restore isn't logging anything, what if its takes more than a few seconds?  I think the user might think something is wrong.  We could pass console logger parameters to produce some output
```
-consoleLoggerParameters:Verbosity=Minimal;NoSummary
```
created_at: 2025-03-26T16:10:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,60 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            restoreExitCode = RunRestore(projectFile, formatOption);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption)
+    {
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: ["-target:restore", projectOrSolution, "-noConsoleLogger"]);
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: jeffkl
body: I also just realized that `dotnet package list` accepts an `--interactive` argument, we'll need to pass that to restore as well.
created_at: 2025-03-26T16:15:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,60 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            restoreExitCode = RunRestore(projectFile, formatOption);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption)
+    {
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: ["-target:restore", projectOrSolution, "-noConsoleLogger"]);
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: baronfel
body: We should try to align with test and run here and use the same logger configuration - ideally this would use terminal logger by default like every other command in the CLI. 
created_at: 2025-03-26T17:29:26Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,60 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            restoreExitCode = RunRestore(projectFile, formatOption);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption)
+    {
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: ["-target:restore", projectOrSolution, "-noConsoleLogger"]);
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: jeffkl
body: I'm not so sure, the output of this command is the information about the packages that a project is referencing. Its not running tests (which are potentially long running) and its not building a project and its dependencies.

The only reason we need to run restore first is because the `project.assets.json` file provides all of the information and we want to make sure its up-to-date. The only reason I propose we have any output at all about restore is in the case that it takes a while, I don't want users to think that `dotnet list package` is hung.
created_at: 2025-03-26T18:05:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Forgind
body: tiny nit: -target:Restore
created_at: 2025-03-27T16:25:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
+        }
+        else
+        {
+            args = ["-target:restore", projectOrSolution, "--consoleLoggerParameters:Verbosity=Minimal;NoSummary"];
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+            MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Forgind
body: What version is this?
created_at: 2025-03-27T16:29:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
+        }
+        else
+        {
+            args = ["-target:restore", projectOrSolution, "--consoleLoggerParameters:Verbosity=Minimal;NoSummary"];
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+            MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
+   "problems": [
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Forgind
body: "errors"? Or since this doesn't really seem to be an array, can we just make it "error" and have it be the object?
created_at: 2025-03-27T16:29:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
+        }
+        else
+        {
+            args = ["-target:restore", projectOrSolution, "--consoleLoggerParameters:Verbosity=Minimal;NoSummary"];
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+            MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
+   "problems": [
+      {
+         "text": "{{String.Format(CultureInfo.CurrentCulture, LocalizableStrings.Error_restore)}}",
+         "level": "error"
+      }
+   ]
+}
+""";
+                Console.WriteLine(jsonError);
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Forgind
body: This feels like it should go elsewhere. Does NuGet normally just write to the console? Seems like there should be some kind of logger, or at least this should go to Console.Error
created_at: 2025-03-27T16:32:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,4 +174,11 @@
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
+    <comment>Do not translate `dotnet restore`</comment>
path: src/Cli/dotnet/Commands/Package/List/LocalizableStrings.resx
user: login: Forgind
body: nit: use the [locking syntax](https://github.com/dotnet/sdk/blob/main/documentation/project-docs/Localization.md#locking-translations) for pinned translation strings so that the Loc team's tooling helps prevent unintentional translation.
created_at: 2025-03-27T16:33:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Forgind
body: I was looking this and comparing it with RestoringCommand. I'm not entirely sure why they look so different. This looks correct, as far as I can tell; I just thought it'd would be nice to combine them if possible.
created_at: 2025-03-27T16:35:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
+        }
+        else
+        {
+            args = ["-target:restore", projectOrSolution, "--consoleLoggerParameters:Verbosity=Minimal;NoSummary"];
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+            MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: It is following the Json schema from https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.CommandLine.XPlat/ListPackage/ListPackageJsonRenderer.cs#L19
created_at: 2025-03-28T19:51:44Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
+        }
+        else
+        {
+            args = ["-target:restore", projectOrSolution, "--consoleLoggerParameters:Verbosity=Minimal;NoSummary"];
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+            MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
+   "problems": [
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: This is following this schema: https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.CommandLine.XPlat/ListPackage/ListPackageJsonRenderer.cs#L19. We want to make sure this does not introduce no new changes to the json schema
created_at: 2025-03-28T19:52:23Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args;
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args = ["-target:restore", projectOrSolution, "-noConsoleLogger"];
+        }
+        else
+        {
+            args = ["-target:restore", projectOrSolution, "--consoleLoggerParameters:Verbosity=Minimal;NoSummary"];
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+            MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
+        }
+
+        if (exitCode != 0)
+        {
+            if (formatOption == ReportOutputFormat.json)
+            {
+                string jsonError = $$"""
+{
+   "version": 1,
+   "problems": [
+      {
+         "text": "{{String.Format(CultureInfo.CurrentCulture, LocalizableStrings.Error_restore)}}",
+         "level": "error"
+      }
+   ]
+}
+""";
+                Console.WriteLine(jsonError);
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: For the dotnet package list command, NuGet writes to Conosle.out
created_at: 2025-03-28T20:06:41Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,73 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: zivkan
body: some customers run `dotnet list package` in CI pipelines, where they are not interactive.  This needs to be toggleable.
created_at: 2025-03-28T22:26:27Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,73 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: I was assuming the default is false. but upon reading the docs, there is nothing that backs my assumption.
created_at: 2025-03-28T23:02:32Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,72 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: I looked into using `RestoringCommand` here as well, but decided against it for a few reasons:

- `RestoringCommand` is primarily looks like it is built for commands like `build`, where restore may need to run either in-process (`-restore`) or as a separate `msbuild -target:Restore` call. In our case, we explicitly want to run only restore, and we already know what MSBuild target to run 

- Even when `--no-restore` is passed, `RestoringCommand` still invokes `MSBuildForwardingApp.Execute()` with the provided arguments. Even if no arguments are passed at all, it could end up building the project unintentionally due to MSBuild's default behavior.


created_at: 2025-03-28T23:14:45Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,78 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: jebriede
body: Nit: This method does a lot of things to prepare the command to run. Consider adding private helper methods to set up the options and generate the json output and call them from this method.
created_at: 2025-04-08T17:46:25Z
author_association: NONE
diff_hunk: @@ -174,4 +174,11 @@
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
-</root>
\ No newline at end of file
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
path: src/Cli/dotnet/Commands/Package/List/LocalizableStrings.resx
user: login: jebriede
body: Question: Is this wording consistent with other output or was this wording vetted?
created_at: 2025-04-08T17:49:37Z
author_association: NONE
diff_hunk: @@ -30,7 +32,78 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+        else
+        {
+            args.Add("-interactive:false");
+        }
+
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: aortiz-msft
body: What are valid exitCodes, and does this have the potential to overwrite a more helpful exitCode with a less helpful one?
created_at: 2025-04-08T18:03:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -30,7 +32,78 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+        else
+        {
+            args.Add("-interactive:false");
+        }
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: aortiz-msft
body: Suggestion: args.add("-interactive:" + Convert.ToString(interactive));
created_at: 2025-04-08T18:05:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,4 +174,11 @@
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
-</root>
\ No newline at end of file
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
path: src/Cli/dotnet/Commands/Package/List/LocalizableStrings.resx
user: login: Forgind
body: On that note, why can't we output the error from dotnet restore without them having to run dotnet restore explicitly?
created_at: 2025-04-08T19:28:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,4 +174,11 @@
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
-</root>
\ No newline at end of file
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
path: src/Cli/dotnet/Commands/Package/List/LocalizableStrings.resx
user: login: Nigusu-Allehu
body: > Question: Is this wording consistent with other output or was this wording vetted?

This the first adoption of implicit restore for nuget commands. Others like dotnet nuget why will probably follow suit as well.

> On that note, why can't we output the error from dotnet restore without them having to run dotnet restore explicitly?

When the command includes `--format json`, we avoid printing any additional output to ensure the JSON remains valid. To enforce this, I passed `-noConsoleLogger` to MSBuild. Since this operation runs in a separate process, capturing and displaying errors becomes tricky. If we were running the restore in-process, however, we could have easily captured the errors and logged them ourselves.

created_at: 2025-04-08T23:42:44Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,78 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+        else
+        {
+            args.Add("-interactive:false");
+        }
+
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: 1 - for failure
0 - for success
https://github.com/NuGet/NuGet.Client/blob/ab6b96fd9ba07ed3bf629ee389799ca4fb9a20fb/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/ListPackage/ListPackageCommandRunner.cs#L31
created_at: 2025-04-08T23:48:30Z
author_association: MEMBER
diff_hunk: @@ -30,7 +32,78 @@ private static string GetAbsolutePath(string currentDirectory, string relativePa
 
     public override int Execute()
     {
-        return NuGetCommand.Run(TransformArgs());
+        string projectFile = GetProjectOrSolution();
+        bool noRestore = _parseResult.HasOption(PackageListCommandParser.NoRestore);
+        int restoreExitCode = 0;
+
+        if (!noRestore)
+        {
+            ReportOutputFormat formatOption = _parseResult.GetValue((CliOption<ReportOutputFormat>)PackageListCommandParser.FormatOption);
+            bool interactive = _parseResult.GetValue((CliOption<bool>)PackageListCommandParser.InteractiveOption);
+            restoreExitCode = RunRestore(projectFile, formatOption, interactive);
+        }
+
+        return restoreExitCode == 0
+            ? NuGetCommand.Run(TransformArgs(projectFile))
+            : restoreExitCode;
+    }
+
+    private int RunRestore(string projectOrSolution, ReportOutputFormat formatOption, bool interactive)
+    {
+        List<string> args = ["-target:Restore", projectOrSolution];
+
+        if (formatOption == ReportOutputFormat.json)
+        {
+            args.Add("-noConsoleLogger");
+        }
+        else
+        {
+            args.Add("-consoleLoggerParameters:NoSummary");
+            args.Add("-verbosity:minimal");
+        }
+
+        if (interactive)
+        {
+            args.Add("-interactive:true");
+        }
+        else
+        {
+            args.Add("-interactive:false");
+        }
+
+        MSBuildForwardingApp restoringCommand = new MSBuildForwardingApp(argsToForward: args);
+
+        int exitCode = 0;
+
+        try
+        {
+            exitCode = restoringCommand.Execute();
+        }
+        catch (Exception)
+        {
+            exitCode = 1;
path: src/Cli/dotnet/Commands/Package/List/ListPackageReferencesCommand.cs
user: login: Nigusu-Allehu
body: These are the exit codes we use for the dotnet package list command
created_at: 2025-04-08T23:49:45Z
author_association: MEMBER
diff_hunk: @@ -174,4 +174,11 @@
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
-</root>
\ No newline at end of file
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
path: src/Cli/dotnet/Commands/Package/List/LocalizableStrings.resx
user: login: Forgind
body: I actually think this is a perfectly valid response, but I'll bang this drum on baronfel's behalf:
Output should go to stdout. Errors (and other incidental output) should go to stderr. That way you can have beautiful, clean output in stdout and still have access to all the information you'd want in stderr.

I'm assuming NuGet doesn't do that historically, so you're sending errors to stdout as well just because that's how it currently works?

Though if you're going to get an error anyway, does the user really still care that the output of --format json is preserved?
created_at: 2025-04-09T00:02:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,4 +174,11 @@
   <data name="CmdOutputVersionDescription" xml:space="preserve">
     <value>Specifies the version of machine-readable output. Requires the '--format json' option.</value>
   </data>
-</root>
\ No newline at end of file
+  <data name="Error_restore" xml:space="preserve">
+    <value>Restore failed. Run `dotnet restore` for more details on the issue.</value>
path: src/Cli/dotnet/Commands/Package/List/LocalizableStrings.resx
user: login: Nigusu-Allehu
body: That is good point! Tracking here now https://github.com/NuGet/Home/issues/14239
created_at: 2025-04-09T15:23:33Z
author_association: MEMBER

PR comments:
user: login: Nigusu-Allehu
created_at: 2025-04-07T23:38:25Z
body: review request: @dotnet/nuget-team any suggestions/comments? The more time this takes the more conflicts keep coming up
author_association: MEMBER
user: login: marcpopMSFT
created_at: 2025-04-08T20:32:52Z
body: @Nigusu-Allehu there are a bunch of conflicts to resolve fyi.
author_association: MEMBER
user: login: dotnet-policy-service[bot]
created_at: 2025-04-15T17:17:29Z
body: @Nigusu-Allehu: Added `needs-breaking-change-doc-created` label because this PR has the `breaking-change` label. 

When you commit this breaking change:

1. [x] Create and link to this PR and the issue a matching issue in the dotnet/docs repo using the [breaking change documentation template](https://aka.ms/dotnet/docs/new-breaking-change-issue), then remove this `needs-breaking-change-doc-created` label.
2. [ ] Ask a committer to mail the `.NET SDK Breaking Change Notification` email list.

You can refer to the [.NET SDK breaking change guidelines](https://github.com/dotnet/sdk/blob/main/documentation/project-docs/breaking-change-guidelines.md)
<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
author_association: CONTRIBUTOR
user: login: Nigusu-Allehu
created_at: 2025-05-13T18:42:31Z
body: breaking change doc: https://github.com/dotnet/docs/issues/46103
author_association: MEMBER
user: login: Nigusu-Allehu
created_at: 2025-10-09T23:19:40Z
body: doc: https://github.com/dotnet/docs/pull/49053
author_association: MEMBER