diff --git a/.idea/.idea.aeqw89.tools.Publish/.idea/.gitignore b/.idea/.idea.aeqw89.tools.Publish/.idea/.gitignore
new file mode 100644
index 0000000..2784543
--- /dev/null
+++ b/.idea/.idea.aeqw89.tools.Publish/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/projectSettingsUpdater.xml
+/.idea.aeqw89.tools.Publish.iml
+/modules.xml
+/contentModel.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.aeqw89.tools.Publish/.idea/encodings.xml b/.idea/.idea.aeqw89.tools.Publish/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.aeqw89.tools.Publish/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.aeqw89.tools.Publish/.idea/indexLayout.xml b/.idea/.idea.aeqw89.tools.Publish/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.aeqw89.tools.Publish/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.aeqw89.tools.Publish/.idea/vcs.xml b/.idea/.idea.aeqw89.tools.Publish/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.aeqw89.tools.Publish/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aeqw89.tools.Publish.sln b/aeqw89.tools.Publish.sln
new file mode 100644
index 0000000..5edac2c
--- /dev/null
+++ b/aeqw89.tools.Publish.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aeqw89.tools.Publish", "aeqw89.tools.Publish\aeqw89.tools.Publish.csproj", "{B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7F78AEB-BAC3-4D34-A655-BC0B5677EA42}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/aeqw89.tools.Publish.sln.DotSettings.user b/aeqw89.tools.Publish.sln.DotSettings.user
new file mode 100644
index 0000000..57d78f9
--- /dev/null
+++ b/aeqw89.tools.Publish.sln.DotSettings.user
@@ -0,0 +1,15 @@
+
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ True
+ True
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/.gitignore b/aeqw89.tools.Publish/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/aeqw89.tools.Publish/Content.cs b/aeqw89.tools.Publish/Content.cs
new file mode 100644
index 0000000..03a7e7a
--- /dev/null
+++ b/aeqw89.tools.Publish/Content.cs
@@ -0,0 +1,7 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal sealed class Content : Item {
+ public Content(XmlElement node) : base(node) { }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/Exceptions.Designer.cs b/aeqw89.tools.Publish/Exceptions.Designer.cs
new file mode 100644
index 0000000..ce608e7
--- /dev/null
+++ b/aeqw89.tools.Publish/Exceptions.Designer.cs
@@ -0,0 +1,224 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace aeqw89.tools.Publish {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Exceptions {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Exceptions() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("aeqw89.tools.Publish.Exceptions", typeof(Exceptions).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The cloud host '{0}' is not an entry on this user's config file..
+ ///
+ internal static string cloud_host_not_found {
+ get {
+ return ResourceManager.GetString("cloud_host_not_found", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The mode '{0}' is invalid, the valid modes are [overwrite|increment].
+ ///
+ internal static string could_not_parse_mode {
+ get {
+ return ResourceManager.GetString("could_not_parse_mode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The increment target '{0}' is invalid, the valid increment targets are [patch|minor|patch].
+ ///
+ internal static string could_not_parse_target {
+ get {
+ return ResourceManager.GetString("could_not_parse_target", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'dotnet nuget push' command failed with error message '{0}'.
+ ///
+ internal static string dotnet_nuget_push_failure {
+ get {
+ return ResourceManager.GetString("dotnet_nuget_push_failure", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failed to pack; ensure that 'dotnet build' succeeds before running this program..
+ ///
+ internal static string dotnet_pack_failure {
+ get {
+ return ResourceManager.GetString("dotnet_pack_failure", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Could not delete temporary directory '{0}' due to error '{1}'.
+ ///
+ internal static string failed_to_clean_up {
+ get {
+ return ResourceManager.GetString("failed_to_clean_up", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failde to prepare an upload directory on the path {0} for the remote host '{1}', after being detected as a {2} host. Server error is '{3}'.
+ ///
+ internal static string failed_to_prepare_server_directory {
+ get {
+ return ResourceManager.GetString("failed_to_prepare_server_directory", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The flag '{0}' requires exactly '{1}' parameters. You have entered '{2}'..
+ ///
+ internal static string flag_parameter_length_incorrect {
+ get {
+ return ResourceManager.GetString("flag_parameter_length_incorrect", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The '{0}' flag requires that argument with index '{1}' be of type '{2}'. You have entered '{3}' which has failed to be converted..
+ ///
+ internal static string flag_parameter_type_incorrect {
+ get {
+ return ResourceManager.GetString("flag_parameter_type_incorrect", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The directory '{0}' contains multiple .csproj files; this tool can only process one at a time..
+ ///
+ internal static string found_multiple_csproj {
+ get {
+ return ResourceManager.GetString("found_multiple_csproj", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Something went wrong loading this file; {0}.
+ ///
+ internal static string generic_error {
+ get {
+ return ResourceManager.GetString("generic_error", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to You must specify at least one destination..
+ ///
+ internal static string missing_destinations {
+ get {
+ return ResourceManager.GetString("missing_destinations", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to You must specify an increment target if you specified an increment mode; allowed increment targets are [patch|minor|major].
+ ///
+ internal static string missing_increment_target {
+ get {
+ return ResourceManager.GetString("missing_increment_target", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to You must specify a mode; allowed modes are [overwrite|increment].
+ ///
+ internal static string missing_mode {
+ get {
+ return ResourceManager.GetString("missing_mode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to No project file was found within the current directory..
+ ///
+ internal static string no_project_in_directory {
+ get {
+ return ResourceManager.GetString("no_project_in_directory", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The project file '{0}' is irreparable becuase it is missing a '{1}' property, and the value cannot be guessed..
+ ///
+ internal static string project_file_irreparable {
+ get {
+ return ResourceManager.GetString("project_file_irreparable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Something went wrong; an attempt was made to load a non .csproj file as a project file..
+ ///
+ internal static string tried_loading_non_csproj_file {
+ get {
+ return ResourceManager.GetString("tried_loading_non_csproj_file", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The version string '{0}' is in an unidentifiable format..
+ ///
+ internal static string version_string_not_formatted_correctly {
+ get {
+ return ResourceManager.GetString("version_string_not_formatted_correctly", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/aeqw89.tools.Publish/Exceptions.resx b/aeqw89.tools.Publish/Exceptions.resx
new file mode 100644
index 0000000..640185f
--- /dev/null
+++ b/aeqw89.tools.Publish/Exceptions.resx
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ You must specify a mode; allowed modes are [overwrite|increment]
+
+
+ The mode '{0}' is invalid, the valid modes are [overwrite|increment]
+
+
+ The increment target '{0}' is invalid, the valid increment targets are [patch|minor|patch]
+
+
+ You must specify an increment target if you specified an increment mode; allowed increment targets are [patch|minor|major]
+
+
+ You must specify at least one destination.
+
+
+ No project file was found within the current directory.
+
+
+ The flag '{0}' requires exactly '{1}' parameters. You have entered '{2}'.
+
+
+ The '{0}' flag requires that argument with index '{1}' be of type '{2}'. You have entered '{3}' which has failed to be converted.
+
+
+ The version string '{0}' is in an unidentifiable format.
+
+
+ Something went wrong; an attempt was made to load a non .csproj file as a project file.
+
+
+ Something went wrong loading this file; {0}
+
+
+ The directory '{0}' contains multiple .csproj files; this tool can only process one at a time.
+
+
+ The project file '{0}' is irreparable becuase it is missing a '{1}' property, and the value cannot be guessed.
+
+
+ Failed to pack; ensure that 'dotnet build' succeeds before running this program.
+
+
+ Could not delete temporary directory '{0}' due to error '{1}'
+
+
+ The cloud host '{0}' is not an entry on this user's config file.
+
+
+ Failde to prepare an upload directory on the path {0} for the remote host '{1}', after being detected as a {2} host. Server error is '{3}'
+
+
+ The 'dotnet nuget push' command failed with error message '{0}'
+
+
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/IncrementTarget.cs b/aeqw89.tools.Publish/IncrementTarget.cs
new file mode 100644
index 0000000..57242c8
--- /dev/null
+++ b/aeqw89.tools.Publish/IncrementTarget.cs
@@ -0,0 +1,7 @@
+namespace aeqw89.tools.Publish;
+
+public enum IncrementTarget {
+ Patch,
+ Minor,
+ Major,
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/Item.cs b/aeqw89.tools.Publish/Item.cs
new file mode 100644
index 0000000..6a4ed7e
--- /dev/null
+++ b/aeqw89.tools.Publish/Item.cs
@@ -0,0 +1,55 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal class Item {
+ public string ElementName { get; protected set; }
+ public string Include {
+ get => Node.GetAttribute("Include");
+ set => Node.SetAttribute("Include", value);
+ }
+
+ public string Version {
+ get => Node.GetAttribute("Version");
+ set => Node.SetAttribute("Version", value);
+ }
+
+ public string? Value {
+ get => Node.InnerText;
+ set { Node.InnerText = value ?? string.Empty; }
+ }
+ public XmlElement Node { get; }
+
+ protected Item(XmlElement node) {
+ Node = node;
+ ElementName = node.Name;
+ }
+
+ public static Item FromElement(XmlElement element) {
+ return element.Name switch {
+ "PackageReference" => new PackageReference(element),
+ "ProjectReference" => new ProjectReference(element),
+ "Content" => new Content(element),
+ _ => new Item(element),
+ };
+ }
+
+ public void AddChild(Item child) {
+ var imported = Node.OwnerDocument!.ImportNode(child.Node, true);
+ Node.AppendChild(imported);
+ }
+
+ public string? GetAttribute(string name) => Node.HasAttribute(name) ? Node.GetAttribute(name) : null;
+ public void SetAttribute(string name, string? value) {
+ if (value is null) {
+ if (Node.HasAttribute(name)) Node.RemoveAttribute(name);
+ return;
+ }
+ Node.SetAttribute(name, value);
+ }
+
+ public IEnumerable- GetChildElements() {
+ foreach (var e in Node.ChildNodes.OfType())
+ yield return new Item(e);
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/ItemGroup.cs b/aeqw89.tools.Publish/ItemGroup.cs
new file mode 100644
index 0000000..88824a4
--- /dev/null
+++ b/aeqw89.tools.Publish/ItemGroup.cs
@@ -0,0 +1,26 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal class ItemGroup {
+ private readonly XmlElement _element;
+ public List
- Items { get; }
+
+ public void Remove() {
+ _element.ParentNode!.RemoveChild(_element);
+ }
+
+ public ItemGroup(XmlElement element) {
+ _element = element;
+ Items = element.ChildNodes
+ .OfType()
+ .Select(Item.FromElement)
+ .ToList();
+ }
+
+ public void Add(Item item) {
+ var imported = _element.OwnerDocument!.ImportNode(item.Node, true);
+ _element.AppendChild(imported);
+ Items.Add(Item.FromElement((XmlElement)imported));
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/Mode.cs b/aeqw89.tools.Publish/Mode.cs
new file mode 100644
index 0000000..8d13c46
--- /dev/null
+++ b/aeqw89.tools.Publish/Mode.cs
@@ -0,0 +1,6 @@
+namespace aeqw89.tools.Publish;
+
+public enum Mode {
+ Overwrite,
+ Increment,
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/PackageReference.cs b/aeqw89.tools.Publish/PackageReference.cs
new file mode 100644
index 0000000..7413954
--- /dev/null
+++ b/aeqw89.tools.Publish/PackageReference.cs
@@ -0,0 +1,30 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal sealed class PackageReference : Item {
+ public PackageReference(XmlElement node) : base(node) { }
+
+ // inside PackageReference
+ public string? GetPackageVersion() {
+ // Prefer attribute, then child
+ var attr = GetAttribute("Version");
+ if (!string.IsNullOrEmpty(attr)) return attr;
+
+ var child = Node.SelectSingleNode("./Version") as XmlElement;
+ return child?.InnerText;
+ }
+
+ public void SetPackageVersion(string? version) {
+ if (Node.HasAttribute("Version") || (Node.SelectSingleNode("./Version") == null)) {
+ // If attribute exists (or no child yet), use attribute
+ SetAttribute("Version", version);
+ return;
+ }
+
+ // Else write to existing child
+ var child = (XmlElement)Node.SelectSingleNode("./Version")!;
+ child.InnerText = version ?? string.Empty;
+ }
+
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/PrivateAssetsValue.cs b/aeqw89.tools.Publish/PrivateAssetsValue.cs
new file mode 100644
index 0000000..39e923a
--- /dev/null
+++ b/aeqw89.tools.Publish/PrivateAssetsValue.cs
@@ -0,0 +1,6 @@
+namespace aeqw89.tools.Publish;
+
+public enum PrivateAssetsValue {
+ All,
+ None,
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/Program.cs b/aeqw89.tools.Publish/Program.cs
new file mode 100644
index 0000000..8a37de3
--- /dev/null
+++ b/aeqw89.tools.Publish/Program.cs
@@ -0,0 +1,473 @@
+using System.Collections;
+using System.Diagnostics;
+using Renci.SshNet;
+using Spectre.Console;
+using Spectre.Console.Cli;
+using VsTools.Projects;
+
+namespace aeqw89.tools.Publish;
+
+/*
+ * Structure of the program:
+ * - publish (executable)
+ * - overwrite
+ * - destinations
+ * - flags
+ * - increment
+ * - patch|minor|major
+ * - destinations
+ * - flags
+ * e.g. publish overwrite|increment [patch|minor|major] destinations [flags]
+ */
+
+public static class Program {
+ public static Mode Mode { get; set; }
+ public static IncrementTarget? Target { get; set; }
+ public static string[] Destinations { get; set; }
+ public static Dictionary Flags { get; set; }
+ public static bool Verbose { get; set; } = false;
+
+ public static void ReadArgs(string[] args) {
+ if (args.Length < 1) {
+ ShowError(Exceptions.missing_mode.EscapeMarkup());
+ ShowHelp();
+ return;
+ }
+
+ Mode = args[0] switch {
+ "overwrite" => Mode.Overwrite,
+ "increment" => Mode.Increment,
+ _ => (Mode)(-1)
+ };
+
+ if (Mode == (Mode)(-1)) {
+ ShowError(Exceptions.could_not_parse_mode.EscapeMarkup(), args[0].EscapeMarkup());
+ ShowHelp();
+ return;
+ }
+
+ if (args.Length < 2) {
+ if (Mode == Mode.Increment)
+ ShowError(Exceptions.missing_increment_target.EscapeMarkup());
+ else if (Mode == Mode.Overwrite)
+ ShowError(Exceptions.missing_destinations.EscapeMarkup());
+ ShowHelp();
+ return;
+ }
+
+ Destinations = args[1..];
+ Flags = [];
+ if (Mode == Mode.Increment) {
+ if (args.Length < 3) {
+ ShowError(Exceptions.missing_destinations.EscapeMarkup());
+ ShowHelp();
+ return;
+ }
+
+ Destinations = args[2..];
+
+ Target = args[1] switch {
+ "patch" => IncrementTarget.Patch,
+ "minor" => IncrementTarget.Minor,
+ "major" => IncrementTarget.Major,
+ _ => (IncrementTarget)(-1)
+ };
+
+ if (Target == (IncrementTarget)(-1)) {
+ ShowError(Exceptions.could_not_parse_target.EscapeMarkup(), args[1].EscapeMarkup());
+ ShowHelp();
+ return;
+ }
+ }
+
+ string? firstFlag = Destinations.FirstOrDefault(x => x.StartsWith('-'));
+ if (firstFlag == null) return;
+ string[] flags = Destinations.SkipWhile(x => x != firstFlag).ToArray();
+ Flags = ReadFlags(flags);
+ Destinations = Destinations.TakeWhile(x => x != firstFlag).ToArray();
+ Verbose = Flags.ContainsKey("--verbose") || Flags.ContainsKey("-v");
+ }
+
+ private static Dictionary ReadFlags(string[] flags) {
+ Dictionary result = [];
+ List collected = [];
+ string lastKey = flags[0];
+ if (flags.Length == 1)
+ result[lastKey] = [];
+ foreach (var flag in flags.Skip(1)) {
+ if (flag.StartsWith('-')) {
+ result[lastKey] = collected.ToArray();
+ collected = [];
+ lastKey = flag;
+ } else
+ collected.Add(flag);
+ }
+
+ return result;
+ }
+
+ public static async Task Main(string[] args) {
+ ReadArgs(args);
+
+ string packageId = "";
+ string version = "";
+
+ var result = AnsiConsole.Status()
+ .Spinner(Spinner.Known.Dots)
+ .Start("Preparing project", ctx => {
+ ctx.Status = "Locating project file";
+ if (!ProjectFile.TryLoad(Environment.CurrentDirectory, out var projectFile, out var error)) {
+ ShowError(error.EscapeMarkup());
+ return false;
+ }
+
+ packageId = projectFile.GetPackageId();
+
+ try {
+ projectFile.Backup();
+ if (Verbose)
+ AnsiConsole.WriteLine(
+ $"Created project file backup at {projectFile.GetDefaultBackupLocation()}");
+
+ ctx.Status = "Repairing project file";
+ if (!Flags.ContainsKey("--skip-repair"))
+ if (!projectFile.TryRepair(out error)) {
+ ShowError(error.EscapeMarkup());
+ projectFile.Restore();
+ return false;
+ }
+
+ if (Mode == Mode.Increment && !Flags.ContainsKey("--simulate")) {
+ int delta = 1;
+ if (Flags.TryGetValue("--delta", out var deltaStrings)) {
+ if (deltaStrings.Length != 1) {
+ ShowError(Exceptions.flag_parameter_length_incorrect.EscapeMarkup(), "--delta", 1,
+ deltaStrings.Length);
+ projectFile.Restore();
+ ShowHelp();
+ return false;
+ }
+
+ if (!int.TryParse(deltaStrings[0], out delta)) {
+ ShowError(Exceptions.flag_parameter_type_incorrect.EscapeMarkup(), "--delta", 0, nameof(Int32),
+ deltaStrings[0]);
+ projectFile.Restore();
+ ShowHelp();
+ return false;
+ }
+ }
+
+ ctx.Status = "Updating version";
+ var version = projectFile.GetVersion();
+ version = ChangeVersion(version,
+ Target == IncrementTarget.Patch ? delta : 0,
+ Target == IncrementTarget.Minor ? delta : 0,
+ Target == IncrementTarget.Major ? delta : 0,
+ (x, y) => x + y);
+
+ projectFile.SetVersion(version);
+ }
+ }
+ catch (Exception e) {
+ ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup());
+ projectFile.Restore();
+ return false;
+ }
+
+ version = projectFile.GetVersion();
+
+ if (!Flags.ContainsKey("--simulate")) {
+ try {
+ var packageReferences = projectFile.GetPackageReferences();
+ foreach (var reference in packageReferences.Where(x => !projectFile.IsTransitive(x)))
+ projectFile.SetPrivateAssets(reference, PrivateAssetsValue.All);
+ foreach (var reference in packageReferences.Where(x => projectFile.IsTransitive(x)))
+ projectFile.RemovePackage(reference);
+
+ HashSet visited = [];
+ var projectReferences = new Queue
- (projectFile.GetProjectReferences().Cast
- ());
+ while (projectReferences.Count != 0) {
+ var reference = projectReferences.Dequeue();
+ visited.Add(reference.Include);
+
+ if (Verbose)
+ AnsiConsole.WriteLine($"Processing project reference {reference.Include} out of {visited.Count} so far");
+
+ projectFile.SetPrivateAssets(reference, PrivateAssetsValue.All);
+ string pathToReferencedProjectFile = projectFile.GetAbsoluteIncludePath(reference);
+ if (!ProjectFile.TryLoad(pathToReferencedProjectFile, out var referencedProjectFile,
+ out error)) {
+ ShowError(error.EscapeMarkup());
+ projectFile.Restore();
+ return false;
+ }
+
+ var referencedPackageReferences = referencedProjectFile.GetPackageReferences();
+ foreach (var package in referencedPackageReferences) {
+ if (Verbose)
+ AnsiConsole.WriteLine($"Hoisting package {package.Include} from {pathToReferencedProjectFile}");
+ var hoisted = projectFile.AddPackage(package);
+ projectFile.SetTransitive(hoisted, true);
+ projectFile.SetPrivateAssets(hoisted, PrivateAssetsValue.None);
+ referencedProjectFile.SetPrivateAssets(package, PrivateAssetsValue.All);
+ }
+
+ var referencedProjectReferences = referencedProjectFile.GetProjectReferences();
+ foreach (var project in referencedProjectReferences) {
+ if (!visited.Contains(project.Include))
+ projectReferences.Enqueue(project);
+ }
+ }
+ } catch (Exception e) {
+ ShowError(Exceptions.generic_error.EscapeMarkup(), e.ToString().EscapeMarkup());
+ projectFile.Restore();
+ return false;
+ }
+ }
+
+ projectFile.Save();
+ return true;
+ });
+
+ if (!result) {
+ return;
+ }
+
+ var outDir = Path.GetRandomFileName();
+ result = AnsiConsole.Status()
+ .Spinner(Spinner.Known.Dots)
+ .Start("Creating package with 'dotnet pack' ", ctx => {
+ var p = Process.Start(new ProcessStartInfo() {
+ FileName = "dotnet",
+ Arguments = $"pack -o {outDir}",
+ WorkingDirectory = Environment.CurrentDirectory,
+ UseShellExecute = Verbose,
+ RedirectStandardOutput = !Verbose,
+ RedirectStandardError = !Verbose
+ });
+ p?.WaitForExit();
+ return p?.ExitCode == 0;
+ });
+
+ if (!result) {
+ ShowError(Exceptions.dotnet_pack_failure.EscapeMarkup());
+ return;
+ }
+
+ var package = Directory.GetFiles(outDir, "*.nupkg").FirstOrDefault();
+ if (package == null) {
+ ShowError(Exceptions.generic_error.EscapeMarkup());
+ return;
+ }
+
+ var inMemory = await File.ReadAllBytesAsync(package);
+ var size = new FileInfo(package).Length;
+ const long bufferSize = 80 * 1024; // 80 KB
+ try {
+ await AnsiConsole.Progress()
+ .AutoClear(true)
+ .HideCompleted(true)
+ .Columns(new ProgressColumn[] {
+ new TaskDescriptionColumn(),
+ new ProgressBarColumn()
+ .RemainingStyle(Style.Parse("dim gray slowblink"))
+ .CompletedStyle(Style.Parse("green strikethrough"))
+ .FinishedStyle("green strikethrough"),
+ new DownloadedColumn(),
+ new RemainingTimeColumn(),
+ new TransferSpeedColumn(),
+ })
+ .StartAsync(async ctx => {
+ await Parallel.ForEachAsync(Destinations, new ParallelOptions() {
+ MaxDegreeOfParallelism = Environment.ProcessorCount,
+ }, async (dest, ct) => {
+ using var reader = new MemoryStream(inMemory);
+ var task = ctx.AddTask(dest, new ProgressTaskSettings() {
+ MaxValue = size
+ });
+
+ if (dest.StartsWith("local-")) {
+ var name = dest[("local-".Length)..];
+ var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
+ name, Path.GetFileName(package));
+ if (!Directory.Exists(Path.GetDirectoryName(path)))
+ Directory.CreateDirectory(Path.GetDirectoryName(path)!);
+ await using var writer = File.OpenWrite(path);
+ var buffer = new byte[bufferSize];
+ int read;
+ do {
+ read = await reader.ReadAsync(buffer, ct);
+ writer.Write(buffer, 0, read);
+ task.Increment(read);
+ } while (read > 0);
+ }
+
+ else if (dest.StartsWith("cloud-")) {
+ var name = dest[("cloud-".Length)..];
+ var connectionTask = ctx.AddTaskBefore($"Preparing cloud-{name}", new ProgressTaskSettings() {
+ MaxValue = 100
+ }, task);
+
+ if (!SshHosts.TryGetHost(name, out var host)) {
+ ShowError(Exceptions.cloud_host_not_found.EscapeMarkup(), name);
+ return;
+ }
+
+ var connectionInfo = SshHosts.GetConnection(name);
+ using var sshClient = new SshClient(connectionInfo);
+ if (!sshClient.IsConnected)
+ await sshClient.ConnectAsync(ct);
+ connectionTask.Increment(33);
+
+ var winC = sshClient.RunCommand("cmd /c ver");
+ var othC = sshClient.RunCommand("uname -s");
+
+ var os = (winC.ExitStatus, othC.ExitStatus) switch {
+ (0, _) => "windows",
+ (_, 0) => "linux",
+ _ => "unknown"
+ };
+
+ string remoteDirectory;
+ string packageFileDirectory;
+ if (os == "windows") {
+ var userDirC = sshClient.RunCommand("cmd /c echo %USERPROFILE%");
+ if (userDirC.ExitStatus != 0) {
+ ShowError(Exceptions.failed_to_prepare_server_directory, "n/a", name, os, userDirC.Result);
+ return;
+ }
+
+ var userDir = userDirC.Result.Trim();
+ remoteDirectory = RemotePath.Combine(RemoteOs.Windows,userDir, "dotnet-packages");
+ packageFileDirectory = RemotePath.Combine(RemoteOs.Windows, remoteDirectory, Path.GetFileName(package));
+
+ var mkdirC = sshClient.RunCommand($"cmd /c if not exist \"{remoteDirectory}\" mkdir \"{remoteDirectory}\"");
+ if (mkdirC.ExitStatus != 0) {
+ ShowError(Exceptions.failed_to_prepare_server_directory, remoteDirectory, name, os, mkdirC.Result);
+ return;
+ }
+ }
+ else if (os == "linux") {
+ var homeDirC = sshClient.RunCommand("printf %s \"$HOME\"");
+ if (homeDirC.ExitStatus != 0) {
+ ShowError(Exceptions.failed_to_prepare_server_directory, "n/a", name, os, homeDirC.Result);
+ return;
+ }
+ var homeDir = homeDirC.Result.Trim(); // no CRLF on unix, but Trim() is safest
+ remoteDirectory = RemotePath.Combine(RemoteOs.Unix, homeDir, ".dotnet-packages");
+ packageFileDirectory = RemotePath.Combine(RemoteOs.Unix, remoteDirectory, Path.GetFileName(package));
+
+ // Use -p and single quotes to handle spaces safely
+ var mkdirC = sshClient.RunCommand($"mkdir -p '{remoteDirectory}'");
+ if (mkdirC.ExitStatus != 0) {
+ ShowError(Exceptions.failed_to_prepare_server_directory, remoteDirectory, name, os, mkdirC.Result);
+ return;
+ }
+ }
+ else {
+ ShowError(Exceptions.failed_to_prepare_server_directory, "n/a", name, os, "Unsupported OS");
+ return;
+ }
+ connectionTask.Increment(33);
+
+ sshClient.Disconnect();
+
+ using var client = new SftpClient(connectionInfo);
+ if (!client.IsConnected)
+ await client.ConnectAsync(ct);
+ connectionTask.Increment(33);
+ connectionTask.StopTask();
+
+ await using var writer = client.OpenWrite(packageFileDirectory);
+ byte[] buffer = new byte[bufferSize];
+ int read;
+ do {
+ read = await reader.ReadAsync(buffer, ct);
+ writer.Write(buffer, 0, read);
+ task.Increment(read);
+ } while (read > 0);
+ }
+
+ else if (dest == "github") {
+ var p = Process.Start(new ProcessStartInfo() {
+ FileName = "dotnet",
+ Arguments = $"nuget push {package} --source github",
+ WorkingDirectory = Environment.CurrentDirectory,
+ UseShellExecute = false,
+ RedirectStandardOutput = !Verbose,
+ RedirectStandardError = !Verbose
+ });
+
+ if (p == null) {
+ ShowError(Exceptions.generic_error.EscapeMarkup());
+ }
+
+ task.Increment(size / 2);
+ if (p != null)
+ await p.WaitForExitAsync(ct);
+ if (p?.ExitCode != 0) {
+ ShowError(Exceptions.dotnet_nuget_push_failure, p.ExitCode);
+ }
+ task.Increment(size / 2);
+ }
+
+ task.StopTask();
+ });
+ });
+ }
+ finally {
+ try {
+ Directory.Delete(outDir, true);
+ }
+ catch (Exception e) {
+ ShowError(string.Format(Exceptions.failed_to_clean_up.EscapeMarkup(), outDir.EscapeMarkup(), e.ToString().EscapeMarkup()));
+ }
+ }
+ AnsiConsole.MarkupLine("Completed processing of all destinations.");
+ AnsiConsole.MarkupLine("Example usage:\n\t ".EscapeMarkup(), packageId, version);
+ }
+
+ ///
+ /// Updates the version string by applying the specified operation to the major, minor, and patch components of the version.
+ ///
+ /// The current version string in the format "major.minor.patch[-tag]".
+ /// The value to apply to the patch component.
+ /// The value to apply to the minor component.
+ /// The value to apply to the major component.
+ /// A function that defines the adjustment operation to be performed on each version component.
+ /// A new version string with the updated major, minor, and patch components, preserving any existing tag.
+ /// Thrown if the version string is not in the correct format.
+ private static string ChangeVersion(string version, int patch, int minor, int major,
+ Func operation) {
+ string[] split = version.Split('.');
+ if (split.Length != 3) {
+ throw new Exception(string.Format(Exceptions.version_string_not_formatted_correctly, version));
+ }
+
+ string tag = "";
+ if (split[2].Contains('-')) {
+ var split2 = split[2].Split('-');
+ split[2] = split2[0];
+ tag = "-" + split2[1];
+ }
+
+ if (split.Any(x => !int.TryParse(x, out _)))
+ throw new Exception(string.Format(Exceptions.version_string_not_formatted_correctly, version));
+
+ int[] parsedVersion = split.Select(int.Parse).ToArray();
+
+ return
+ $"{operation(parsedVersion[0], major)}.{operation(parsedVersion[1], minor)}.{operation(parsedVersion[2], patch)}{tag}";
+ }
+
+ private static void ShowError(string message, params object[] args) {
+ AnsiConsole.MarkupLine($"[bold red]{message}[/]", args);
+ }
+
+ private static void ShowHelp() {
+ AnsiConsole.Markup(("Usage: publish overwrite|increment [patch|minor|major] destinations [flags]\n" +
+ "\t if mode: overwrite destinations [flags]\n" +
+ "\t if mode: increment patch|minor|major [flags]\n").EscapeMarkup());
+
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/Project.cs b/aeqw89.tools.Publish/Project.cs
new file mode 100644
index 0000000..c5d2e73
--- /dev/null
+++ b/aeqw89.tools.Publish/Project.cs
@@ -0,0 +1,54 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal class Project {
+ public string Path { get; }
+ private XmlDocument Document { get; }
+ public List PropertyGroups { get; }
+ public List ItemGroups { get; }
+
+ private Project(string path, XmlDocument doc) {
+ Path = path;
+ Document = doc;
+
+ // Build PropertyGroups
+ PropertyGroups = doc.DocumentElement!
+ .SelectNodes("./PropertyGroup")!
+ .OfType()
+ .Select(e => new PropertyGroup(e))
+ .ToList();
+
+ // Build ItemGroups (+ their Items)
+ ItemGroups = doc.DocumentElement!
+ .SelectNodes("./ItemGroup")!
+ .OfType()
+ .Select(e => new ItemGroup(e))
+ .ToList();
+
+ // Ensure at least one ItemGroup exists (some csprojs omit it until first item is added)
+ if (ItemGroups.Count == 0) {
+ var ig = doc.CreateElement("ItemGroup", doc.DocumentElement!.NamespaceURI);
+ doc.DocumentElement!.AppendChild(ig);
+ ItemGroups.Add(new ItemGroup((XmlElement)ig));
+ }
+ }
+
+ public static Project Load(string path) {
+ var doc = new XmlDocument();
+ doc.PreserveWhitespace = false;
+ doc.Load(path);
+ return new Project(path, doc);
+ }
+
+ public void Save() {
+ var settings = new XmlWriterSettings {
+ Indent = true,
+ IndentChars = " ",
+ NewLineChars = Environment.NewLine,
+ NewLineHandling = NewLineHandling.Replace
+ };
+ using var writer = XmlWriter.Create(Path, settings);
+ Document.Save(writer);
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/ProjectFile.cs b/aeqw89.tools.Publish/ProjectFile.cs
new file mode 100644
index 0000000..20f1270
--- /dev/null
+++ b/aeqw89.tools.Publish/ProjectFile.cs
@@ -0,0 +1,216 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+// -------------------------------------------------------------------------------------------------
+// Minimal replacements for VsTools.Projects so ProjectFile can keep its public surface intact
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+// Your original public surface, now backed by System.Xml
+// -------------------------------------------------------------------------------------------------
+
+internal class ProjectFile {
+ public Project Project { get; private set; }
+ public string Path { get; private set; }
+ private PropertyGroup MainPropertyGroup { get; set; }
+
+ private ProjectFile(Project project, string path) {
+ MainPropertyGroup = project.PropertyGroups.FirstOrDefault()!;
+ Project = project;
+ Path = path;
+ }
+
+ public static bool TryLoad(string path, [NotNullWhen(true)] out ProjectFile? projectFile, [NotNullWhen(false)] out string? error) {
+ projectFile = null;
+ error = null;
+
+ if (!path.EndsWith(".csproj")) {
+ if (!Directory.Exists(path)) {
+ error = Exceptions.tried_loading_non_csproj_file;
+ return false;
+ }
+
+ var csproj = Directory.EnumerateFiles(path, "*.csproj", SearchOption.TopDirectoryOnly).ToArray();
+ if (csproj.Length == 0) {
+ error = Exceptions.no_project_in_directory;
+ return false;
+ }
+
+ if (csproj.Length > 1) {
+ error = Exceptions.found_multiple_csproj;
+ return false;
+ }
+
+ path = csproj[0];
+ }
+
+ try {
+ projectFile = new ProjectFile(Project.Load(path), path);
+ return true;
+ }
+ catch (Exception e) {
+ error = string.Format(Exceptions.generic_error, e);
+ return false;
+ }
+ }
+
+ public void Backup(string? backupPath = null) {
+ backupPath ??= Path + ".bak";
+ File.Copy(Path, backupPath, true);
+ }
+
+ public string GetDefaultBackupLocation() => Path + ".bak";
+
+ public bool Restore(string? backupPath = null) {
+ backupPath ??= GetDefaultBackupLocation();
+ if (!File.Exists(backupPath)) return false;
+ File.Copy(backupPath, Path, true);
+ return true;
+ }
+
+ public void Save() {
+ // Check for empty property or item groups
+ foreach (var ig in Project.ItemGroups.ToList().Where(ig => ig.Items.Count == 0)) {
+ ig.Remove();
+ }
+ foreach (var pg in Project.PropertyGroups.ToList().Where(pg => pg.Count == 0)) {
+ pg.Remove();
+ }
+
+ Project.Save();
+ }
+
+ public bool TryRepair([NotNullWhen(false)] out string? error) {
+ // Ensure we have a PropertyGroup with TargetFramework
+ if (MainPropertyGroup?.HasProperty("TargetFramework") != true) {
+ if (!Project.PropertyGroups.Any(x => x.HasProperty("TargetFramework"))) {
+ error = string.Format(Exceptions.project_file_irreparable, Path, "TargetFramework");
+ return false;
+ }
+ MainPropertyGroup = Project.PropertyGroups.First(x => x.HasProperty("TargetFramework"));
+ }
+
+ List failed = [];
+
+ void set(string key, string value, bool required = false) {
+ if (!MainPropertyGroup.HasProperty(key) || string.IsNullOrEmpty(MainPropertyGroup.GetProperty(key))) {
+ if (required) {
+ failed.Add(key);
+ return;
+ }
+ MainPropertyGroup.SetProperty(key, value);
+ }
+ }
+
+ set("Version", "1.0.0");
+ set("Title", System.IO.Path.GetFileNameWithoutExtension(Path));
+ set("Authors", "");
+ set("Company", "");
+ set("Description", "");
+ set("PackageProjectUrl", "", required: false);
+ set("RepositoryUrl", "", required: true);
+ set("PackageId", "", required: true);
+
+ if (failed.Count > 0) {
+ error = string.Format(Exceptions.project_file_irreparable, Path, string.Join(", ", failed));
+ return false;
+ }
+
+ error = null;
+ return true;
+ }
+
+ public List GetPackageReferences() {
+ return Project.ItemGroups
+ .SelectMany(g => g.Items)
+ .Where(i => i.ElementName == "PackageReference")
+ .OfType()
+ .ToList();
+ }
+
+ public List GetProjectReferences() {
+ return Project.ItemGroups
+ .SelectMany(g => g.Items)
+ .Where(i => i.ElementName == "ProjectReference")
+ .OfType()
+ .ToList();
+ }
+
+ public List GetPackageDependencies() {
+ return Project.ItemGroups
+ .SelectMany(g => g.Items)
+ .Where(i => i.ElementName == "Content")
+ .OfType()
+ .ToList();
+ }
+
+ private void CreateOrUpdateChild(Item item, string childName, string value) {
+ var child = item.Node.SelectSingleNode(childName) as XmlElement;
+ if (child != null) {
+ child.InnerText = value;
+ return;
+ }
+
+ child = item.Node.OwnerDocument!.CreateElement(childName, item.Node.NamespaceURI);
+ child.InnerText = value;
+ item.Node.AppendChild(child);
+ }
+
+ public string GetPackageId() {
+ return MainPropertyGroup.GetProperty("PackageId");
+ }
+
+ public void SetPrivateAssets(Item item, PrivateAssetsValue value) {
+ if (value == PrivateAssetsValue.None) {
+ var child = item.Node.SelectSingleNode("./PrivateAssets") as XmlElement;
+ if (child != null)
+ item.Node.RemoveChild(child);
+ return;
+ }
+
+ CreateOrUpdateChild(item, "PrivateAssets", value.ToString().ToLowerInvariant());
+ }
+
+ public void SetTransitive(Item item, bool value)
+ => CreateOrUpdateChild(item, "Transitive", value.ToString().ToLowerInvariant());
+
+ public bool IsTransitive(Item item) {
+ var transitive = item.Node.SelectSingleNode("./Transitive") as XmlElement;
+ return transitive?.InnerText == "true";
+ }
+
+ public string GetAbsoluteIncludePath(Item item) {
+ return System.IO.Path.GetFullPath(item.Include);
+ }
+
+ public Item AddPackage(Item otherPackage) {
+ var allItems = Project.ItemGroups.SelectMany(x => x.Items);
+ var existing = allItems.FirstOrDefault(x =>
+ x.ElementName == "PackageReference" && x.Include == otherPackage.Include);
+ if (existing != null) return existing;
+
+ var itemGroup = Project.ItemGroups.First();
+ // Import the original XmlElement to preserve Version (attr or child) and any metadata
+ itemGroup.Add(otherPackage);
+ return itemGroup.Items.Last();
+ }
+
+
+ public bool RemovePackage(Item otherPackage) {
+ var grp = Project.ItemGroups
+ .FirstOrDefault(g => g.Items.Any(y => y.ElementName == "PackageReference" && y.Include == otherPackage.Include));
+
+ var pkg = grp?.Items.FirstOrDefault(x => x.ElementName == otherPackage.ElementName && x.Include == otherPackage.Include);
+ if (pkg == null) return false;
+
+ pkg.Node.ParentNode!.RemoveChild(pkg.Node);
+ grp!.Items.Remove(pkg);
+ return true;
+ }
+
+ public string GetVersion() => MainPropertyGroup.GetProperty("Version");
+
+ public void SetVersion(string version) => MainPropertyGroup.SetProperty("Version", version);
+}
diff --git a/aeqw89.tools.Publish/ProjectReference.cs b/aeqw89.tools.Publish/ProjectReference.cs
new file mode 100644
index 0000000..acf6799
--- /dev/null
+++ b/aeqw89.tools.Publish/ProjectReference.cs
@@ -0,0 +1,7 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal sealed class ProjectReference : Item {
+ public ProjectReference(XmlElement node) : base(node) { }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/PropertyGroup.cs b/aeqw89.tools.Publish/PropertyGroup.cs
new file mode 100644
index 0000000..56f966f
--- /dev/null
+++ b/aeqw89.tools.Publish/PropertyGroup.cs
@@ -0,0 +1,28 @@
+using System.Xml;
+
+namespace aeqw89.tools.Publish;
+
+internal class PropertyGroup {
+ private readonly XmlElement _element;
+ public PropertyGroup(XmlElement element) => _element = element;
+
+ public bool HasProperty(string name) => _element.SelectSingleNode($"./{name}") is XmlElement;
+
+ public string GetProperty(string name) {
+ var node = _element.SelectSingleNode($"./{name}") as XmlElement;
+ return node?.InnerText ?? string.Empty;
+ }
+
+ public void SetProperty(string name, string value) {
+ var node = _element.SelectSingleNode($"./{name}") as XmlElement;
+ if (node == null) {
+ node = _element.OwnerDocument!.CreateElement(name, _element.NamespaceURI);
+ _element.AppendChild(node);
+ }
+ node.InnerText = value ?? string.Empty;
+ }
+
+ public int Count => _element.ChildNodes.OfType().Count();
+
+ public void Remove() => _element.ParentNode!.RemoveChild(_element);
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/RemotePath.cs b/aeqw89.tools.Publish/RemotePath.cs
new file mode 100644
index 0000000..6f9d29b
--- /dev/null
+++ b/aeqw89.tools.Publish/RemotePath.cs
@@ -0,0 +1,90 @@
+// Required namespaces: System, System.Linq, System.Text.RegularExpressions
+
+using System.Text.RegularExpressions;
+
+namespace aeqw89.tools.Publish;
+
+public enum RemoteOs { Windows, Unix }
+
+public static partial class RemotePath
+{
+ public static string Combine(RemoteOs os, params string[] parts)
+ {
+ if (parts == null || parts.Length == 0) return string.Empty;
+
+ // Normalize null/empty segments and trim whitespace
+ var cleaned = parts.Where(p => !string.IsNullOrWhiteSpace(p))
+ .Select(p => p.Trim())
+ .ToArray();
+ if (cleaned.Length == 0) return string.Empty;
+
+ return os == RemoteOs.Windows
+ ? CombineWindows(cleaned)
+ : CombineUnix(cleaned);
+ }
+
+ private static string CombineUnix(string[] parts)
+ {
+ // Keep a single leading '/' if the first segment is rooted
+ bool rooted = parts[0].StartsWith("/", StringComparison.Ordinal);
+ var body = parts.Select((p, i) =>
+ {
+ var s = p.Replace("\\", "/");
+ // Trim both ends except preserve leading '/' only for first segment
+ if (i == 0)
+ return s.TrimEnd('/');
+ return s.Trim('/'); // internal segments never carry separators
+ })
+ .Where(s => s.Length > 0)
+ .ToArray();
+
+ var joined = string.Join("/", body);
+ return rooted ? (joined.StartsWith("/") ? joined : "/" + joined) : joined;
+ }
+
+ private static string CombineWindows(string[] parts)
+ {
+ // Windows separators are backslashes for cmd.exe/PowerShell paths.
+ // Preserve drive letters like "C:" and UNC roots like "\\server".
+ var first = parts[0].Replace("/", "\\").Trim();
+ var rest = parts.Skip(1)
+ .Select(p => p.Replace("/", "\\").Trim('\\'))
+ .Where(s => s.Length > 0)
+ .ToArray();
+
+ // Detect UNC root (\\server\share...) or device prefix (\\?\ or \\.\)
+ bool isUncOrDevice = first.StartsWith(@"\\", StringComparison.Ordinal);
+ bool isDrive = IsDrive().IsMatch(first);
+
+ if (isUncOrDevice)
+ {
+ // Keep exactly two leading backslashes; trim trailing ones
+ first = @"\\" + first.TrimStart('\\').TrimEnd('\\');
+ }
+ else if (isDrive)
+ {
+ // Normalize "C:" or "C:\" to "C:\"
+ first = first.Length == 2 ? first + "\\" : first;
+ }
+ else
+ {
+ // For relative first segment, strip surrounding slashes
+ first = first.Trim('\\');
+ }
+
+ string joined = rest.Length > 0
+ ? first + (first.EndsWith("\\") ? "" : "\\") + string.Join("\\", rest)
+ : first;
+
+ // Collapse any accidental doubles that can appear from user input (but keep UNC prefix)
+ if (!joined.StartsWith(@"\\"))
+ joined = Collapse().Replace(joined, @"\");
+
+ return joined;
+ }
+
+ [System.Text.RegularExpressions.GeneratedRegex(@"^[A-Za-z]:\\?$")]
+ private static partial System.Text.RegularExpressions.Regex IsDrive();
+ [GeneratedRegex(@"\\{2,}")]
+ private static partial Regex Collapse();
+}
diff --git a/aeqw89.tools.Publish/SshHosts.cs b/aeqw89.tools.Publish/SshHosts.cs
new file mode 100644
index 0000000..ff6ada2
--- /dev/null
+++ b/aeqw89.tools.Publish/SshHosts.cs
@@ -0,0 +1,423 @@
+// Required namespaces:
+// System, System.IO, System.Linq, System.Text, System.Text.RegularExpressions, System.Collections.Generic, Renci.SshNet
+
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace aeqw89.tools.Publish;
+
+public record Host(
+ string Name,
+ string Hostname,
+ string User,
+ string Password,
+ int Port,
+ List IdentityFiles,
+ Renci.SshNet.ProxyTypes? ProxyType,
+ string? ProxyHost,
+ int? ProxyPort,
+ string? ProxyUser,
+ string? ProxyPassword
+);
+
+public static class SshHosts {
+ public static List Hosts { get; set; }
+
+ static SshHosts() {
+ Hosts = new List();
+
+ var path = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
+ ".ssh",
+ "config"
+ );
+
+ if (!File.Exists(path)) return;
+
+ var lines = File.ReadAllLines(path);
+
+ string[]? currentNames = null;
+ string? currentHostName = null;
+ string? currentUser = null;
+ string? currentPassword = null;
+ int? currentPort = null;
+ List? currentIdentityFiles = null;
+
+ // Proxy (explicit)
+ Renci.SshNet.ProxyTypes? currentProxyType = null;
+ string? currentProxyHost = null;
+ int? currentProxyPort = null;
+ string? currentProxyUser = null;
+ string? currentProxyPassword = null;
+
+ // Proxy (derived from ProxyCommand)
+ string? currentProxyCommand = null;
+
+ void ResetBlock()
+ {
+ currentNames = null;
+ currentHostName = null;
+ currentUser = null;
+ currentPassword = null;
+ currentPort = null;
+ currentIdentityFiles = null;
+
+ currentProxyType = null;
+ currentProxyHost = null;
+ currentProxyPort = null;
+ currentProxyUser = null;
+ currentProxyPassword = null;
+
+ currentProxyCommand = null;
+ }
+
+ void MaybeDeriveProxyFromProxyCommand()
+ {
+ if (string.IsNullOrWhiteSpace(currentProxyCommand)) return;
+ if (currentProxyType != null && currentProxyHost != null && currentProxyPort != null) return;
+
+ // Very common forms:
+ // nc -x host:port -X 5 %h %p (SOCKS5)
+ // nc -x host:port -X 4 %h %p (SOCKS4)
+ // nc -x host:port %h %p (default: treat as SOCKS5)
+ // nc -X connect -x host:port %h %p (HTTP CONNECT)
+ // connect -S host:port %h %p (treat as SOCKS5)
+ var s = currentProxyCommand;
+
+ // host:port extraction
+ var hp = Regex.Match(s, @"(?:(?:-x|-S)\s+|\s)([A-Za-z0-9.\-]+):(\d{1,5})");
+ if (hp.Success) {
+ currentProxyHost ??= hp.Groups[1].Value;
+ if (int.TryParse(hp.Groups[2].Value, out var pp) && pp > 0 && pp <= 65535)
+ currentProxyPort ??= pp;
+ }
+
+ // type extraction
+ if (Regex.IsMatch(s, @"-X\s+5\b", RegexOptions.IgnoreCase))
+ currentProxyType ??= Renci.SshNet.ProxyTypes.Socks5;
+ else if (Regex.IsMatch(s, @"-X\s+4\b", RegexOptions.IgnoreCase))
+ currentProxyType ??= Renci.SshNet.ProxyTypes.Socks4;
+ else if (Regex.IsMatch(s, @"-X\s+connect\b", RegexOptions.IgnoreCase))
+ currentProxyType ??= Renci.SshNet.ProxyTypes.Http;
+ else if (s.Contains("connect ", System.StringComparison.OrdinalIgnoreCase))
+ currentProxyType ??= Renci.SshNet.ProxyTypes.Http;
+ else if (s.Contains("nc ", System.StringComparison.OrdinalIgnoreCase))
+ currentProxyType ??= Renci.SshNet.ProxyTypes.Socks5;
+
+ // If we still don't have enough, leave proxy unset.
+ }
+
+ void Flush()
+ {
+ if (currentNames == null || currentNames.Length == 0) {
+ ResetBlock();
+ return;
+ }
+
+ // Try deriving proxy from ProxyCommand if explicit values weren't set
+ MaybeDeriveProxyFromProxyCommand();
+
+ foreach (var n in currentNames) {
+ var hn = string.IsNullOrWhiteSpace(currentHostName) ? n : currentHostName!;
+ var idFiles = new List();
+ if (currentIdentityFiles != null) {
+ foreach (var f in currentIdentityFiles) idFiles.Add(ExpandPath(f));
+ }
+
+ Hosts.Add(new Host(
+ Name: n,
+ Hostname: hn,
+ User: currentUser ?? string.Empty,
+ Password: currentPassword ?? string.Empty,
+ Port: currentPort ?? 22,
+ IdentityFiles: idFiles,
+ ProxyType: currentProxyType,
+ ProxyHost: currentProxyHost,
+ ProxyPort: currentProxyPort,
+ ProxyUser: currentProxyUser,
+ ProxyPassword: currentProxyPassword
+ ));
+ }
+
+ ResetBlock();
+ }
+
+ foreach (var raw in lines) {
+ var line = raw.Trim();
+ if (line.Length == 0 || line.StartsWith("#")) continue;
+
+ int idx = line.IndexOfAny(new[] { ' ', '\t' });
+ string key, value;
+ if (idx < 0) {
+ key = line;
+ value = string.Empty;
+ } else {
+ key = line[..idx];
+ value = line[idx..].Trim();
+ }
+
+ switch (key.ToLowerInvariant()) {
+ case "host":
+ Flush();
+ currentNames = SplitArgs(value).ToArray();
+ break;
+
+ case "hostname":
+ if (currentNames != null) currentHostName = value;
+ break;
+
+ case "user":
+ if (currentNames != null) currentUser = value;
+ break;
+
+ case "password":
+ // Non-standard; supported here as a convenience (used for password auth or key passphrase)
+ if (currentNames != null) currentPassword = value;
+ break;
+
+ case "port":
+ if (currentNames != null && int.TryParse(value, out var p) && p > 0 && p <= 65535)
+ currentPort = p;
+ break;
+
+ case "identityfile":
+ if (currentNames != null) {
+ currentIdentityFiles ??= new List();
+ foreach (var f in SplitArgs(value)) {
+ if (!string.IsNullOrWhiteSpace(f)) currentIdentityFiles.Add(f);
+ }
+ }
+ break;
+
+ // --- Proxy settings (explicit custom keys) ---
+ case "proxytype":
+ if (currentNames != null) {
+ var v = value.ToLowerInvariant();
+ currentProxyType =
+ v switch {
+ "socks5" or "socks" or "socks5h" => Renci.SshNet.ProxyTypes.Socks5,
+ "socks4" => Renci.SshNet.ProxyTypes.Socks4,
+ "http" or "https" or "connect" => Renci.SshNet.ProxyTypes.Http,
+ _ => currentProxyType
+ };
+ }
+ break;
+
+ case "proxyhost":
+ if (currentNames != null) currentProxyHost = value;
+ break;
+
+ case "proxyport":
+ if (currentNames != null && int.TryParse(value, out var prxP) && prxP > 0 && prxP <= 65535)
+ currentProxyPort = prxP;
+ break;
+
+ case "proxyuser":
+ if (currentNames != null) currentProxyUser = value;
+ break;
+
+ case "proxypassword":
+ if (currentNames != null) currentProxyPassword = value;
+ break;
+
+ // --- OpenSSH-style hints we try to interpret ---
+ case "proxycommand":
+ if (currentNames != null) currentProxyCommand = value;
+ break;
+
+ // (Note: ProxyJump is non-trivial to replicate in SSH.NET; not parsed here.)
+
+ default:
+ break;
+ }
+ }
+
+ Flush();
+ }
+
+ // Builds a ConnectionInfo from a parsed host, ensuring all ~/.ssh private keys are tried.
+ private static Renci.SshNet.ConnectionInfo BuildConnection(Host h) {
+ var authMethods = new List();
+
+ // 1) Collect candidate key file paths: from config + everything that looks like a private key in ~/.ssh
+ var keyPaths = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var f in h.IdentityFiles)
+ if (!string.IsNullOrWhiteSpace(f))
+ keyPaths.Add(f);
+
+ foreach (var f in EnumerateAllSshPrivateKeys())
+ keyPaths.Add(f);
+
+ // 2) Load keys (try with passphrase, then without)
+ var pkFiles = new List();
+ foreach (var p in keyPaths) {
+ if (!File.Exists(p)) continue;
+ try {
+ if (!string.IsNullOrEmpty(h.Password)) {
+ try {
+ pkFiles.Add(new Renci.SshNet.PrivateKeyFile(p, h.Password));
+ continue;
+ }
+ catch { /* fall through to try without passphrase */
+ }
+ }
+
+ pkFiles.Add(new Renci.SshNet.PrivateKeyFile(p));
+ }
+ catch { /* skip unreadable/unparsable key */
+ }
+ }
+
+ if (pkFiles.Count > 0)
+ authMethods.Add(new Renci.SshNet.PrivateKeyAuthenticationMethod(h.User, pkFiles.ToArray()));
+
+ // 3) Optional password auth (remote account password)
+ if (!string.IsNullOrEmpty(h.Password))
+ authMethods.Add(new Renci.SshNet.PasswordAuthenticationMethod(h.User, h.Password));
+
+ if (authMethods.Count == 0)
+ throw new InvalidOperationException($"No authentication methods available for host '{h.Name}'.");
+
+ // 4) Proxy-aware ConnectionInfo
+ if (h.ProxyType.HasValue && !string.IsNullOrWhiteSpace(h.ProxyHost) && h.ProxyPort.HasValue) {
+ return new Renci.SshNet.ConnectionInfo(
+ h.Hostname,
+ h.Port,
+ h.User,
+ h.ProxyType.Value,
+ h.ProxyHost!,
+ h.ProxyPort.Value,
+ h.ProxyUser,
+ h.ProxyPassword,
+ authMethods.ToArray()
+ );
+ }
+
+ return new Renci.SshNet.ConnectionInfo(h.Hostname, h.Port, h.User, authMethods.ToArray());
+ }
+
+ // Enumerate everything in ~/.ssh that *looks* like a private key.
+ // Skips obvious non-keys like *.pub, known_hosts, config, and directories.
+ private static IEnumerable EnumerateAllSshPrivateKeys() {
+ var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ var sshDir = Path.Combine(home, ".ssh");
+ if (!Directory.Exists(sshDir)) yield break;
+
+ // Common private key basenames to prioritize
+ var preferred = new HashSet(StringComparer.OrdinalIgnoreCase) {
+ "id_rsa", "id_ecdsa", "id_ed25519", "id_dsa"
+ };
+
+ // First yield preferred names if present
+ foreach (var name in preferred) {
+ var p = Path.Combine(sshDir, name);
+ if (File.Exists(p)) yield return p;
+ }
+
+ // Then yield everything else that looks like a key
+ foreach (var file in Directory.EnumerateFiles(sshDir)) {
+ var name = Path.GetFileName(file);
+
+ // Skip ones we already yielded
+ if (preferred.Contains(name)) continue;
+
+ // Exclude common non-key files and public keys
+ if (name.EndsWith(".pub", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.Equals("config", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.Equals("known_hosts", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.Equals("authorized_keys", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.EndsWith(".crt", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.EndsWith(".csr", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.EndsWith(".pem.pub", StringComparison.OrdinalIgnoreCase)) continue; // guard for odd combos
+ if (name.EndsWith(".txt", StringComparison.OrdinalIgnoreCase)) continue;
+ if (name.EndsWith(".conf", StringComparison.OrdinalIgnoreCase)) continue;
+
+ // Heuristic: accept files with no extension, or with .key/.pem
+ var ext = Path.GetExtension(name);
+ if (string.IsNullOrEmpty(ext) ||
+ ext.Equals(".key", StringComparison.OrdinalIgnoreCase) ||
+ ext.Equals(".pem", StringComparison.OrdinalIgnoreCase)) {
+ yield return file;
+ }
+ }
+ }
+
+
+ public static Host Get(string name) {
+ for (int i = 0; i < Hosts.Count; i++) {
+ if (string.Equals(Hosts[i].Name, name, StringComparison.OrdinalIgnoreCase)) {
+ return Hosts[i];
+ }
+ }
+ throw new KeyNotFoundException($"SSH host '{name}' not found.");
+ }
+
+ public static bool TryGetHost(string name, out Host host) {
+ for (int i = 0; i < Hosts.Count; i++) {
+ if (string.Equals(Hosts[i].Name, name, StringComparison.OrdinalIgnoreCase)) {
+ host = Hosts[i];
+ return true;
+ }
+ }
+ host = default!;
+ return false;
+ }
+
+ public static Renci.SshNet.ConnectionInfo GetConnection(string name)
+ {
+ var h = Get(name);
+ return BuildConnection(h);
+ }
+
+ public static bool TryGetConnection(string name, out Renci.SshNet.ConnectionInfo connectionInfo)
+ {
+ if (TryGetHost(name, out var h)) {
+ try {
+ connectionInfo = BuildConnection(h);
+ return true;
+ } catch {
+ // If auth material is unusable, return false.
+ }
+ }
+ connectionInfo = default!;
+ return false;
+ }
+
+ // --- Helpers ---
+
+ // Splits a value into whitespace-delimited tokens while respecting double/single quotes.
+ static IEnumerable SplitArgs(string input)
+ {
+ if (string.IsNullOrWhiteSpace(input)) yield break;
+
+ bool inSingle = false, inDouble = false;
+ var sb = new StringBuilder();
+
+ for (int i = 0; i < input.Length; i++) {
+ char c = input[i];
+
+ if (c == '"' && !inSingle) { inDouble = !inDouble; continue; }
+ if (c == '\'' && !inDouble) { inSingle = !inSingle; continue; }
+
+ if (!inSingle && !inDouble && char.IsWhiteSpace(c)) {
+ if (sb.Length > 0) { yield return sb.ToString(); sb.Clear(); }
+ } else {
+ sb.Append(c);
+ }
+ }
+ if (sb.Length > 0) yield return sb.ToString();
+ }
+
+ // Expands leading "~" to user home. Leaves %h, %r, etc. untouched.
+ static string ExpandPath(string p)
+ {
+ if (string.IsNullOrEmpty(p)) return p;
+ if (p == "~") return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ if (p.StartsWith("~/")) {
+ var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ return Path.Combine(home, p[2..]);
+ }
+ return p;
+ }
+}
diff --git a/aeqw89.tools.Publish/aeqw89.tools.Publish.csproj b/aeqw89.tools.Publish/aeqw89.tools.Publish.csproj
new file mode 100644
index 0000000..26c14ea
--- /dev/null
+++ b/aeqw89.tools.Publish/aeqw89.tools.Publish.csproj
@@ -0,0 +1,32 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Exceptions.Designer.cs
+
+
+
+
+
+ True
+ True
+ Exceptions.resx
+
+
+
+
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/BouncyCastle.Cryptography.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/BouncyCastle.Cryptography.dll
new file mode 100644
index 0000000..bf1a8a1
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/BouncyCastle.Cryptography.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll
new file mode 100644
index 0000000..81ed3de
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/Microsoft.Extensions.Logging.Abstractions.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/Microsoft.Extensions.Logging.Abstractions.dll
new file mode 100644
index 0000000..cedb2b8
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/Microsoft.Extensions.Logging.Abstractions.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/Renci.SshNet.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/Renci.SshNet.dll
new file mode 100644
index 0000000..af01d10
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/Renci.SshNet.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/Spectre.Console.Cli.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/Spectre.Console.Cli.dll
new file mode 100644
index 0000000..25b90d2
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/Spectre.Console.Cli.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/Spectre.Console.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/Spectre.Console.dll
new file mode 100644
index 0000000..14b1118
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/Spectre.Console.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/VsTools.Projects.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/VsTools.Projects.dll
new file mode 100644
index 0000000..ea26afe
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/VsTools.Projects.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.deps.json b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.deps.json
new file mode 100644
index 0000000..d70d30a
--- /dev/null
+++ b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.deps.json
@@ -0,0 +1,176 @@
+{
+ "runtimeTarget": {
+ "name": ".NETCoreApp,Version=v9.0",
+ "signature": ""
+ },
+ "compilationOptions": {},
+ "targets": {
+ ".NETCoreApp,Version=v9.0": {
+ "aeqw89.tools.Publish/1.0.0": {
+ "dependencies": {
+ "SSH.NET": "2025.0.0",
+ "Spectre.Console": "0.51.2-preview.0.1",
+ "Spectre.Console.Cli": "0.51.2-preview.0.1",
+ "VsTools.Projects": "1.2.0"
+ },
+ "runtime": {
+ "aeqw89.tools.Publish.dll": {}
+ }
+ },
+ "BouncyCastle.Cryptography/2.5.1": {
+ "runtime": {
+ "lib/net6.0/BouncyCastle.Cryptography.dll": {
+ "assemblyVersion": "2.0.0.0",
+ "fileVersion": "2.5.1.28965"
+ }
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
+ "runtime": {
+ "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
+ "assemblyVersion": "8.0.0.0",
+ "fileVersion": "8.0.1024.46610"
+ }
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions/8.0.3": {
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ },
+ "runtime": {
+ "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
+ "assemblyVersion": "8.0.0.0",
+ "fileVersion": "8.0.1325.6609"
+ }
+ }
+ },
+ "Spectre.Console/0.51.2-preview.0.1": {
+ "runtime": {
+ "lib/net9.0/Spectre.Console.dll": {
+ "assemblyVersion": "0.0.0.0",
+ "fileVersion": "0.51.2.0"
+ }
+ }
+ },
+ "Spectre.Console.Cli/0.51.2-preview.0.1": {
+ "dependencies": {
+ "Spectre.Console": "0.51.2-preview.0.1"
+ },
+ "runtime": {
+ "lib/net9.0/Spectre.Console.Cli.dll": {
+ "assemblyVersion": "0.0.0.0",
+ "fileVersion": "0.51.2.0"
+ }
+ },
+ "resources": {
+ "lib/net9.0/de/Spectre.Console.Cli.resources.dll": {
+ "locale": "de"
+ },
+ "lib/net9.0/es/Spectre.Console.Cli.resources.dll": {
+ "locale": "es"
+ },
+ "lib/net9.0/fr/Spectre.Console.Cli.resources.dll": {
+ "locale": "fr"
+ },
+ "lib/net9.0/it/Spectre.Console.Cli.resources.dll": {
+ "locale": "it"
+ },
+ "lib/net9.0/ja/Spectre.Console.Cli.resources.dll": {
+ "locale": "ja"
+ },
+ "lib/net9.0/ko/Spectre.Console.Cli.resources.dll": {
+ "locale": "ko"
+ },
+ "lib/net9.0/pt/Spectre.Console.Cli.resources.dll": {
+ "locale": "pt"
+ },
+ "lib/net9.0/ru/Spectre.Console.Cli.resources.dll": {
+ "locale": "ru"
+ },
+ "lib/net9.0/sv/Spectre.Console.Cli.resources.dll": {
+ "locale": "sv"
+ },
+ "lib/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll": {
+ "locale": "zh-Hans"
+ }
+ }
+ },
+ "SSH.NET/2025.0.0": {
+ "dependencies": {
+ "BouncyCastle.Cryptography": "2.5.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.3"
+ },
+ "runtime": {
+ "lib/net9.0/Renci.SshNet.dll": {
+ "assemblyVersion": "2025.0.0.1",
+ "fileVersion": "2025.0.0.1"
+ }
+ }
+ },
+ "VsTools.Projects/1.2.0": {
+ "runtime": {
+ "lib/netstandard2.0/VsTools.Projects.dll": {
+ "assemblyVersion": "1.2.0.0",
+ "fileVersion": "1.2.0.0"
+ }
+ }
+ }
+ }
+ },
+ "libraries": {
+ "aeqw89.tools.Publish/1.0.0": {
+ "type": "project",
+ "serviceable": false,
+ "sha512": ""
+ },
+ "BouncyCastle.Cryptography/2.5.1": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-zy8TMeTP+1FH2NrLaNZtdRbBdq7u5MI+NFZQOBSM69u5RFkciinwzV2eveY6Kjf5MzgsYvvl6kTStsj3JrXqkg==",
+ "path": "bouncycastle.cryptography/2.5.1",
+ "hashPath": "bouncycastle.cryptography.2.5.1.nupkg.sha512"
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==",
+ "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2",
+ "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512"
+ },
+ "Microsoft.Extensions.Logging.Abstractions/8.0.3": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
+ "path": "microsoft.extensions.logging.abstractions/8.0.3",
+ "hashPath": "microsoft.extensions.logging.abstractions.8.0.3.nupkg.sha512"
+ },
+ "Spectre.Console/0.51.2-preview.0.1": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-eTojiXsispvwl5i3o6BsBt0fV7pn+jsJ3nbQVCTCwBoYbeczNO2w7wjPfB2Tx+Y5+mplLEtSFi5Mp0aFZSP3tA==",
+ "path": "spectre.console/0.51.2-preview.0.1",
+ "hashPath": "spectre.console.0.51.2-preview.0.1.nupkg.sha512"
+ },
+ "Spectre.Console.Cli/0.51.2-preview.0.1": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-sgcQ28dkBJG66JU+BI/vhXvgqYOS+0S2OaW5sYkpShk0MzHO2hnnyg8Ef636NG6U+OmIALVZ69CP3oImeUUrag==",
+ "path": "spectre.console.cli/0.51.2-preview.0.1",
+ "hashPath": "spectre.console.cli.0.51.2-preview.0.1.nupkg.sha512"
+ },
+ "SSH.NET/2025.0.0": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-AKYbB+q2zFkNQbBFx5gXdv+Wje0baBtADQ35WnMKi4bg1ka74wTQtWoPd+fOWcydohdfsD0nfT8ErMOAPxtSfA==",
+ "path": "ssh.net/2025.0.0",
+ "hashPath": "ssh.net.2025.0.0.nupkg.sha512"
+ },
+ "VsTools.Projects/1.2.0": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-Zja9D1HlSi+6goiAYUkcuE1dUC7MyoU4ZiXCNMcQ6JFNloHpwO8ne7cATi4jeMco56TB3Trzv+vtAiK4jDydlw==",
+ "path": "vstools.projects/1.2.0",
+ "hashPath": "vstools.projects.1.2.0.nupkg.sha512"
+ }
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.dll
new file mode 100644
index 0000000..fad0e9b
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.exe b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.exe
new file mode 100644
index 0000000..f4e5b71
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.exe differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.pdb b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.pdb
new file mode 100644
index 0000000..2b60df2
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.pdb differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.runtimeconfig.json b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.runtimeconfig.json
new file mode 100644
index 0000000..b19c3c8
--- /dev/null
+++ b/aeqw89.tools.Publish/bin/Debug/net9.0/aeqw89.tools.Publish.runtimeconfig.json
@@ -0,0 +1,12 @@
+{
+ "runtimeOptions": {
+ "tfm": "net9.0",
+ "framework": {
+ "name": "Microsoft.NETCore.App",
+ "version": "9.0.0"
+ },
+ "configProperties": {
+ "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/de/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/de/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..bd395dd
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/de/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/es/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/es/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..af1475b
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/es/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/fr/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/fr/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..9c85f1f
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/fr/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/it/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/it/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..da89f62
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/it/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/ja/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/ja/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..3976be2
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/ja/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/ko/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/ko/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..135f75c
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/ko/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/pt/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/pt/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..89a1669
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/pt/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/ru/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/ru/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..d758506
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/ru/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/sv/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/sv/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..89ba50f
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/sv/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/bin/Debug/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll b/aeqw89.tools.Publish/bin/Debug/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll
new file mode 100644
index 0000000..63207c4
Binary files /dev/null and b/aeqw89.tools.Publish/bin/Debug/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs b/aeqw89.tools.Publish/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs
new file mode 100644
index 0000000..feda5e9
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs
@@ -0,0 +1,4 @@
+//
+using System;
+using System.Reflection;
+[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.t.65D2674F.Up2Date b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.t.65D2674F.Up2Date
new file mode 100644
index 0000000..e69de29
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.AssemblyInfo.cs b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.AssemblyInfo.cs
new file mode 100644
index 0000000..7f89470
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.AssemblyInfo.cs
@@ -0,0 +1,22 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+[assembly: System.Reflection.AssemblyCompanyAttribute("aeqw89.tools.Publish")]
+[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
+[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
+[assembly: System.Reflection.AssemblyProductAttribute("aeqw89.tools.Publish")]
+[assembly: System.Reflection.AssemblyTitleAttribute("aeqw89.tools.Publish")]
+[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
+
+// Generated by the MSBuild WriteCodeFragment class.
+
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.AssemblyInfoInputs.cache b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.AssemblyInfoInputs.cache
new file mode 100644
index 0000000..2fd6cbf
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.AssemblyInfoInputs.cache
@@ -0,0 +1 @@
+e3dc9f23098d7e7631e5f51a024428b60b92087a4a264306a861bae3c79e94dd
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.Exceptions.resources b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.Exceptions.resources
new file mode 100644
index 0000000..571f5bd
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.Exceptions.resources differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.GeneratedMSBuildEditorConfig.editorconfig b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.GeneratedMSBuildEditorConfig.editorconfig
new file mode 100644
index 0000000..0017265
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.GeneratedMSBuildEditorConfig.editorconfig
@@ -0,0 +1,15 @@
+is_global = true
+build_property.TargetFramework = net9.0
+build_property.TargetPlatformMinVersion =
+build_property.UsingMicrosoftNETSdkWeb =
+build_property.ProjectTypeGuids =
+build_property.InvariantGlobalization =
+build_property.PlatformNeutralAssembly =
+build_property.EnforceExtendedAnalyzerRules =
+build_property._SupportedPlatformList = Linux,macOS,Windows
+build_property.RootNamespace = aeqw89.tools.Publish
+build_property.ProjectDir = C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\
+build_property.EnableComHosting =
+build_property.EnableGeneratedComInterfaceComImportInterop =
+build_property.EffectiveAnalysisLevelStyle = 9.0
+build_property.EnableCodeStyleSeverity =
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.GlobalUsings.g.cs b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.GlobalUsings.g.cs
new file mode 100644
index 0000000..8578f3d
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.GlobalUsings.g.cs
@@ -0,0 +1,8 @@
+//
+global using global::System;
+global using global::System.Collections.Generic;
+global using global::System.IO;
+global using global::System.Linq;
+global using global::System.Net.Http;
+global using global::System.Threading;
+global using global::System.Threading.Tasks;
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.assets.cache b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.assets.cache
new file mode 100644
index 0000000..4f84117
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.assets.cache differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.AssemblyReference.cache b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.AssemblyReference.cache
new file mode 100644
index 0000000..f9c41c0
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.AssemblyReference.cache differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.CoreCompileInputs.cache b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.CoreCompileInputs.cache
new file mode 100644
index 0000000..fda2bd5
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.CoreCompileInputs.cache
@@ -0,0 +1 @@
+5d197b168fe8c90856a81b99d1fce6aff6057143a768436bb5102085caca4cb0
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.FileListAbsolute.txt b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.FileListAbsolute.txt
new file mode 100644
index 0000000..387cef0
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.FileListAbsolute.txt
@@ -0,0 +1,35 @@
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.exe
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.deps.json
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.runtimeconfig.json
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\aeqw89.tools.Publish.pdb
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Spectre.Console.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Spectre.Console.Cli.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\de\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\es\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\fr\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\it\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\ja\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\ko\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\pt\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\ru\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\sv\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\zh-Hans\Spectre.Console.Cli.resources.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.csproj.AssemblyReference.cache
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.Exceptions.resources
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.csproj.GenerateResource.cache
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.GeneratedMSBuildEditorConfig.editorconfig
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.AssemblyInfoInputs.cache
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.AssemblyInfo.cs
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.csproj.CoreCompileInputs.cache
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.t.65D2674F.Up2Date
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\refint\aeqw89.tools.Publish.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.pdb
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\aeqw89.tools.Publish.genruntimeconfig.cache
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\obj\Debug\net9.0\ref\aeqw89.tools.Publish.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\VsTools.Projects.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\BouncyCastle.Cryptography.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Microsoft.Extensions.Logging.Abstractions.dll
+C:\Users\qwsdc\source\repos\aeqw89.tools.Publish\aeqw89.tools.Publish\bin\Debug\net9.0\Renci.SshNet.dll
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.GenerateResource.cache b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.GenerateResource.cache
new file mode 100644
index 0000000..b45758b
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.csproj.GenerateResource.cache differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.dll b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.dll
new file mode 100644
index 0000000..fad0e9b
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.dll differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.genruntimeconfig.cache b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.genruntimeconfig.cache
new file mode 100644
index 0000000..3544434
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.genruntimeconfig.cache
@@ -0,0 +1 @@
+168cdf600308143eb70e75e0de49fe275399afb34dc3d60504d380fe24fdc670
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.pdb b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.pdb
new file mode 100644
index 0000000..2b60df2
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/aeqw89.tools.Publish.pdb differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/apphost.exe b/aeqw89.tools.Publish/obj/Debug/net9.0/apphost.exe
new file mode 100644
index 0000000..f4e5b71
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/apphost.exe differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/ref/aeqw89.tools.Publish.dll b/aeqw89.tools.Publish/obj/Debug/net9.0/ref/aeqw89.tools.Publish.dll
new file mode 100644
index 0000000..3123821
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/ref/aeqw89.tools.Publish.dll differ
diff --git a/aeqw89.tools.Publish/obj/Debug/net9.0/refint/aeqw89.tools.Publish.dll b/aeqw89.tools.Publish/obj/Debug/net9.0/refint/aeqw89.tools.Publish.dll
new file mode 100644
index 0000000..3123821
Binary files /dev/null and b/aeqw89.tools.Publish/obj/Debug/net9.0/refint/aeqw89.tools.Publish.dll differ
diff --git a/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.dgspec.json b/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.dgspec.json
new file mode 100644
index 0000000..d5afa59
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.dgspec.json
@@ -0,0 +1,86 @@
+{
+ "format": 1,
+ "restore": {
+ "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj": {}
+ },
+ "projects": {
+ "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj": {
+ "version": "1.0.0",
+ "restore": {
+ "projectUniqueName": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
+ "projectName": "aeqw89.tools.Publish",
+ "projectPath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
+ "packagesPath": "C:\\Users\\qwsdc\\.nuget\\packages\\",
+ "outputPath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\",
+ "projectStyle": "PackageReference",
+ "configFilePaths": [
+ "C:\\Users\\qwsdc\\AppData\\Roaming\\NuGet\\NuGet.Config"
+ ],
+ "originalTargetFrameworks": [
+ "net9.0"
+ ],
+ "sources": {
+ "https://api.nuget.org/v3/index.json": {},
+ "https://nuget.pkg.github.com/qwsdcvghyu89/index.json": {}
+ },
+ "frameworks": {
+ "net9.0": {
+ "targetAlias": "net9.0",
+ "projectReferences": {}
+ }
+ },
+ "warningProperties": {
+ "warnAsError": [
+ "NU1605"
+ ]
+ },
+ "restoreAuditProperties": {
+ "enableAudit": "true",
+ "auditLevel": "low",
+ "auditMode": "direct"
+ },
+ "SdkAnalysisLevel": "9.0.100"
+ },
+ "frameworks": {
+ "net9.0": {
+ "targetAlias": "net9.0",
+ "dependencies": {
+ "SSH.NET": {
+ "target": "Package",
+ "version": "[2025.0.0, )"
+ },
+ "Spectre.Console": {
+ "target": "Package",
+ "version": "[0.51.2-preview.0.1, )"
+ },
+ "Spectre.Console.Cli": {
+ "target": "Package",
+ "version": "[0.51.2-preview.0.1, )"
+ },
+ "VsTools.Projects": {
+ "target": "Package",
+ "version": "[1.2.0, )"
+ }
+ },
+ "imports": [
+ "net461",
+ "net462",
+ "net47",
+ "net471",
+ "net472",
+ "net48",
+ "net481"
+ ],
+ "assetTargetFallback": true,
+ "warn": true,
+ "frameworkReferences": {
+ "Microsoft.NETCore.App": {
+ "privateAssets": "all"
+ }
+ },
+ "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.g.props b/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.g.props
new file mode 100644
index 0000000..8488116
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.g.props
@@ -0,0 +1,15 @@
+
+
+
+ True
+ NuGet
+ $(MSBuildThisFileDirectory)project.assets.json
+ $(UserProfile)\.nuget\packages\
+ C:\Users\qwsdc\.nuget\packages\
+ PackageReference
+ 6.14.0
+
+
+
+
+
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.g.targets b/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.g.targets
new file mode 100644
index 0000000..67f9f1c
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/aeqw89.tools.Publish.csproj.nuget.g.targets
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/project.assets.json b/aeqw89.tools.Publish/obj/project.assets.json
new file mode 100644
index 0000000..3a0ab3c
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/project.assets.json
@@ -0,0 +1,464 @@
+{
+ "version": 3,
+ "targets": {
+ "net9.0": {
+ "BouncyCastle.Cryptography/2.5.1": {
+ "type": "package",
+ "compile": {
+ "lib/net6.0/BouncyCastle.Cryptography.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net6.0/BouncyCastle.Cryptography.dll": {
+ "related": ".xml"
+ }
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
+ "type": "package",
+ "compile": {
+ "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
+ "related": ".xml"
+ }
+ },
+ "build": {
+ "buildTransitive/net6.0/_._": {}
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions/8.0.3": {
+ "type": "package",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ },
+ "compile": {
+ "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
+ "related": ".xml"
+ }
+ },
+ "build": {
+ "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets": {}
+ }
+ },
+ "Spectre.Console/0.51.2-preview.0.1": {
+ "type": "package",
+ "compile": {
+ "lib/net9.0/Spectre.Console.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net9.0/Spectre.Console.dll": {
+ "related": ".xml"
+ }
+ }
+ },
+ "Spectre.Console.Cli/0.51.2-preview.0.1": {
+ "type": "package",
+ "dependencies": {
+ "Spectre.Console": "0.51.2-preview.0.1"
+ },
+ "compile": {
+ "lib/net9.0/Spectre.Console.Cli.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net9.0/Spectre.Console.Cli.dll": {
+ "related": ".xml"
+ }
+ },
+ "resource": {
+ "lib/net9.0/de/Spectre.Console.Cli.resources.dll": {
+ "locale": "de"
+ },
+ "lib/net9.0/es/Spectre.Console.Cli.resources.dll": {
+ "locale": "es"
+ },
+ "lib/net9.0/fr/Spectre.Console.Cli.resources.dll": {
+ "locale": "fr"
+ },
+ "lib/net9.0/it/Spectre.Console.Cli.resources.dll": {
+ "locale": "it"
+ },
+ "lib/net9.0/ja/Spectre.Console.Cli.resources.dll": {
+ "locale": "ja"
+ },
+ "lib/net9.0/ko/Spectre.Console.Cli.resources.dll": {
+ "locale": "ko"
+ },
+ "lib/net9.0/pt/Spectre.Console.Cli.resources.dll": {
+ "locale": "pt"
+ },
+ "lib/net9.0/ru/Spectre.Console.Cli.resources.dll": {
+ "locale": "ru"
+ },
+ "lib/net9.0/sv/Spectre.Console.Cli.resources.dll": {
+ "locale": "sv"
+ },
+ "lib/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll": {
+ "locale": "zh-Hans"
+ }
+ }
+ },
+ "SSH.NET/2025.0.0": {
+ "type": "package",
+ "dependencies": {
+ "BouncyCastle.Cryptography": "2.5.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.3"
+ },
+ "compile": {
+ "lib/net9.0/Renci.SshNet.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net9.0/Renci.SshNet.dll": {
+ "related": ".xml"
+ }
+ }
+ },
+ "VsTools.Projects/1.2.0": {
+ "type": "package",
+ "compile": {
+ "lib/netstandard2.0/VsTools.Projects.dll": {}
+ },
+ "runtime": {
+ "lib/netstandard2.0/VsTools.Projects.dll": {}
+ }
+ }
+ }
+ },
+ "libraries": {
+ "BouncyCastle.Cryptography/2.5.1": {
+ "sha512": "zy8TMeTP+1FH2NrLaNZtdRbBdq7u5MI+NFZQOBSM69u5RFkciinwzV2eveY6Kjf5MzgsYvvl6kTStsj3JrXqkg==",
+ "type": "package",
+ "path": "bouncycastle.cryptography/2.5.1",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "LICENSE.md",
+ "README.md",
+ "bouncycastle.cryptography.2.5.1.nupkg.sha512",
+ "bouncycastle.cryptography.nuspec",
+ "lib/net461/BouncyCastle.Cryptography.dll",
+ "lib/net461/BouncyCastle.Cryptography.xml",
+ "lib/net6.0/BouncyCastle.Cryptography.dll",
+ "lib/net6.0/BouncyCastle.Cryptography.xml",
+ "lib/netstandard2.0/BouncyCastle.Cryptography.dll",
+ "lib/netstandard2.0/BouncyCastle.Cryptography.xml",
+ "packageIcon.png"
+ ]
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
+ "sha512": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==",
+ "type": "package",
+ "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "Icon.png",
+ "LICENSE.TXT",
+ "PACKAGE.md",
+ "THIRD-PARTY-NOTICES.TXT",
+ "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets",
+ "buildTransitive/net462/_._",
+ "buildTransitive/net6.0/_._",
+ "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets",
+ "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
+ "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
+ "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
+ "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
+ "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
+ "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
+ "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
+ "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
+ "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
+ "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
+ "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
+ "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
+ "microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512",
+ "microsoft.extensions.dependencyinjection.abstractions.nuspec",
+ "useSharedDesignerContext.txt"
+ ]
+ },
+ "Microsoft.Extensions.Logging.Abstractions/8.0.3": {
+ "sha512": "dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==",
+ "type": "package",
+ "path": "microsoft.extensions.logging.abstractions/8.0.3",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "Icon.png",
+ "LICENSE.TXT",
+ "PACKAGE.md",
+ "THIRD-PARTY-NOTICES.TXT",
+ "analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll",
+ "analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll",
+ "analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll",
+ "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
+ "buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets",
+ "buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets",
+ "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets",
+ "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets",
+ "buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets",
+ "lib/net462/Microsoft.Extensions.Logging.Abstractions.dll",
+ "lib/net462/Microsoft.Extensions.Logging.Abstractions.xml",
+ "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll",
+ "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.xml",
+ "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.dll",
+ "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.xml",
+ "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll",
+ "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.xml",
+ "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll",
+ "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml",
+ "microsoft.extensions.logging.abstractions.8.0.3.nupkg.sha512",
+ "microsoft.extensions.logging.abstractions.nuspec",
+ "useSharedDesignerContext.txt"
+ ]
+ },
+ "Spectre.Console/0.51.2-preview.0.1": {
+ "sha512": "eTojiXsispvwl5i3o6BsBt0fV7pn+jsJ3nbQVCTCwBoYbeczNO2w7wjPfB2Tx+Y5+mplLEtSFi5Mp0aFZSP3tA==",
+ "type": "package",
+ "path": "spectre.console/0.51.2-preview.0.1",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "README.md",
+ "lib/net8.0/Spectre.Console.dll",
+ "lib/net8.0/Spectre.Console.xml",
+ "lib/net9.0/Spectre.Console.dll",
+ "lib/net9.0/Spectre.Console.xml",
+ "lib/netstandard2.0/Spectre.Console.dll",
+ "lib/netstandard2.0/Spectre.Console.xml",
+ "logo.png",
+ "spectre.console.0.51.2-preview.0.1.nupkg.sha512",
+ "spectre.console.nuspec"
+ ]
+ },
+ "Spectre.Console.Cli/0.51.2-preview.0.1": {
+ "sha512": "sgcQ28dkBJG66JU+BI/vhXvgqYOS+0S2OaW5sYkpShk0MzHO2hnnyg8Ef636NG6U+OmIALVZ69CP3oImeUUrag==",
+ "type": "package",
+ "path": "spectre.console.cli/0.51.2-preview.0.1",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "README.md",
+ "lib/net8.0/Spectre.Console.Cli.dll",
+ "lib/net8.0/Spectre.Console.Cli.xml",
+ "lib/net8.0/de/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/es/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/fr/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/it/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/ja/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/ko/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/pt/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/ru/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/sv/Spectre.Console.Cli.resources.dll",
+ "lib/net8.0/zh-Hans/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/Spectre.Console.Cli.dll",
+ "lib/net9.0/Spectre.Console.Cli.xml",
+ "lib/net9.0/de/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/es/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/fr/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/it/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/ja/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/ko/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/pt/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/ru/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/sv/Spectre.Console.Cli.resources.dll",
+ "lib/net9.0/zh-Hans/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/Spectre.Console.Cli.dll",
+ "lib/netstandard2.0/Spectre.Console.Cli.xml",
+ "lib/netstandard2.0/de/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/es/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/fr/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/it/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/ja/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/ko/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/pt/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/ru/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/sv/Spectre.Console.Cli.resources.dll",
+ "lib/netstandard2.0/zh-Hans/Spectre.Console.Cli.resources.dll",
+ "logo.png",
+ "spectre.console.cli.0.51.2-preview.0.1.nupkg.sha512",
+ "spectre.console.cli.nuspec"
+ ]
+ },
+ "SSH.NET/2025.0.0": {
+ "sha512": "AKYbB+q2zFkNQbBFx5gXdv+Wje0baBtADQ35WnMKi4bg1ka74wTQtWoPd+fOWcydohdfsD0nfT8ErMOAPxtSfA==",
+ "type": "package",
+ "path": "ssh.net/2025.0.0",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "README.md",
+ "SS-NET-icon-h500.png",
+ "lib/net462/Renci.SshNet.dll",
+ "lib/net462/Renci.SshNet.xml",
+ "lib/net8.0/Renci.SshNet.dll",
+ "lib/net8.0/Renci.SshNet.xml",
+ "lib/net9.0/Renci.SshNet.dll",
+ "lib/net9.0/Renci.SshNet.xml",
+ "lib/netstandard2.0/Renci.SshNet.dll",
+ "lib/netstandard2.0/Renci.SshNet.xml",
+ "lib/netstandard2.1/Renci.SshNet.dll",
+ "lib/netstandard2.1/Renci.SshNet.xml",
+ "ssh.net.2025.0.0.nupkg.sha512",
+ "ssh.net.nuspec"
+ ]
+ },
+ "VsTools.Projects/1.2.0": {
+ "sha512": "Zja9D1HlSi+6goiAYUkcuE1dUC7MyoU4ZiXCNMcQ6JFNloHpwO8ne7cATi4jeMco56TB3Trzv+vtAiK4jDydlw==",
+ "type": "package",
+ "path": "vstools.projects/1.2.0",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "lib/net452/VsTools.Projects.dll",
+ "lib/net462/VsTools.Projects.dll",
+ "lib/net48/VsTools.Projects.dll",
+ "lib/netstandard2.0/VsTools.Projects.dll",
+ "vstools.projects.1.2.0.nupkg.sha512",
+ "vstools.projects.nuspec"
+ ]
+ }
+ },
+ "projectFileDependencyGroups": {
+ "net9.0": [
+ "SSH.NET >= 2025.0.0",
+ "Spectre.Console >= 0.51.2-preview.0.1",
+ "Spectre.Console.Cli >= 0.51.2-preview.0.1",
+ "VsTools.Projects >= 1.2.0"
+ ]
+ },
+ "packageFolders": {
+ "C:\\Users\\qwsdc\\.nuget\\packages\\": {}
+ },
+ "project": {
+ "version": "1.0.0",
+ "restore": {
+ "projectUniqueName": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
+ "projectName": "aeqw89.tools.Publish",
+ "projectPath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
+ "packagesPath": "C:\\Users\\qwsdc\\.nuget\\packages\\",
+ "outputPath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\",
+ "projectStyle": "PackageReference",
+ "configFilePaths": [
+ "C:\\Users\\qwsdc\\AppData\\Roaming\\NuGet\\NuGet.Config"
+ ],
+ "originalTargetFrameworks": [
+ "net9.0"
+ ],
+ "sources": {
+ "https://api.nuget.org/v3/index.json": {},
+ "https://nuget.pkg.github.com/qwsdcvghyu89/index.json": {}
+ },
+ "frameworks": {
+ "net9.0": {
+ "targetAlias": "net9.0",
+ "projectReferences": {}
+ }
+ },
+ "warningProperties": {
+ "warnAsError": [
+ "NU1605"
+ ]
+ },
+ "restoreAuditProperties": {
+ "enableAudit": "true",
+ "auditLevel": "low",
+ "auditMode": "direct"
+ },
+ "SdkAnalysisLevel": "9.0.100"
+ },
+ "frameworks": {
+ "net9.0": {
+ "targetAlias": "net9.0",
+ "dependencies": {
+ "SSH.NET": {
+ "target": "Package",
+ "version": "[2025.0.0, )"
+ },
+ "Spectre.Console": {
+ "target": "Package",
+ "version": "[0.51.2-preview.0.1, )"
+ },
+ "Spectre.Console.Cli": {
+ "target": "Package",
+ "version": "[0.51.2-preview.0.1, )"
+ },
+ "VsTools.Projects": {
+ "target": "Package",
+ "version": "[1.2.0, )"
+ }
+ },
+ "imports": [
+ "net461",
+ "net462",
+ "net47",
+ "net471",
+ "net472",
+ "net48",
+ "net481"
+ ],
+ "assetTargetFallback": true,
+ "warn": true,
+ "frameworkReferences": {
+ "Microsoft.NETCore.App": {
+ "privateAssets": "all"
+ }
+ },
+ "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/project.nuget.cache b/aeqw89.tools.Publish/obj/project.nuget.cache
new file mode 100644
index 0000000..edaeb1a
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/project.nuget.cache
@@ -0,0 +1,16 @@
+{
+ "version": 2,
+ "dgSpecHash": "KOrx7rOcVCU=",
+ "success": true,
+ "projectFilePath": "C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj",
+ "expectedPackageFiles": [
+ "C:\\Users\\qwsdc\\.nuget\\packages\\bouncycastle.cryptography\\2.5.1\\bouncycastle.cryptography.2.5.1.nupkg.sha512",
+ "C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\8.0.2\\microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512",
+ "C:\\Users\\qwsdc\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\8.0.3\\microsoft.extensions.logging.abstractions.8.0.3.nupkg.sha512",
+ "C:\\Users\\qwsdc\\.nuget\\packages\\spectre.console\\0.51.2-preview.0.1\\spectre.console.0.51.2-preview.0.1.nupkg.sha512",
+ "C:\\Users\\qwsdc\\.nuget\\packages\\spectre.console.cli\\0.51.2-preview.0.1\\spectre.console.cli.0.51.2-preview.0.1.nupkg.sha512",
+ "C:\\Users\\qwsdc\\.nuget\\packages\\ssh.net\\2025.0.0\\ssh.net.2025.0.0.nupkg.sha512",
+ "C:\\Users\\qwsdc\\.nuget\\packages\\vstools.projects\\1.2.0\\vstools.projects.1.2.0.nupkg.sha512"
+ ],
+ "logs": []
+}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/project.packagespec.json b/aeqw89.tools.Publish/obj/project.packagespec.json
new file mode 100644
index 0000000..893cc04
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/project.packagespec.json
@@ -0,0 +1 @@
+"restore":{"projectUniqueName":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj","projectName":"aeqw89.tools.Publish","projectPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\aeqw89.tools.Publish.csproj","outputPath":"C:\\Users\\qwsdc\\source\\repos\\aeqw89.tools.Publish\\aeqw89.tools.Publish\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net9.0"],"sources":{"https://api.nuget.org/v3/index.json":{},"https://nuget.pkg.github.com/qwsdcvghyu89/index.json":{}},"frameworks":{"net9.0":{"targetAlias":"net9.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net9.0":{"targetAlias":"net9.0","dependencies":{"SSH.NET":{"target":"Package","version":"[2025.0.0, )"},"Spectre.Console":{"target":"Package","version":"[0.51.2-preview.0.1, )"},"Spectre.Console.Cli":{"target":"Package","version":"[0.51.2-preview.0.1, )"},"VsTools.Projects":{"target":"Package","version":"[1.2.0, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\9.0.101/PortableRuntimeIdentifierGraph.json"}}
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/rider.project.model.nuget.info b/aeqw89.tools.Publish/obj/rider.project.model.nuget.info
new file mode 100644
index 0000000..28e2bc2
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/rider.project.model.nuget.info
@@ -0,0 +1 @@
+17584140259343453
\ No newline at end of file
diff --git a/aeqw89.tools.Publish/obj/rider.project.restore.info b/aeqw89.tools.Publish/obj/rider.project.restore.info
new file mode 100644
index 0000000..c7649ce
--- /dev/null
+++ b/aeqw89.tools.Publish/obj/rider.project.restore.info
@@ -0,0 +1 @@
+17584254157830058
\ No newline at end of file