Repository: microsoft/kiota (csharp)

Issue:
I should be able to generate API Manifest from Kiota
Today, when running Kiota CLI to generate plugins, I can do the following:
```powershell
kiota plugin add --pn sunoWithExtensions --openapi .\suno-openapi-with-extensions.yml --type apimanifest
```
However, the output generated is not an [API Manifest](https://darrelmiller.github.io/api-manifest/draft-miller-api-manifest.html).

When choosing --type apimanifest, the output file should be an API Manifest.

Pull request:
Fixes https://github.com/microsoft/kiota/issues/4491
Fixes https://github.com/microsoft/kiota/issues/4447

Changes include

- Adds the `microsoft` type as that is what is being generated at the moment. 
- Fixes breaking changes from latest update from manifest lib
- Fixes naming of generated manifests to apply to convention of `{plugin-name}-{pluginType}.json`

Patch:
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 34885c1e13..cdb61f49af 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -196,7 +196,10 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["search", "microsoft"],
+      "args": [
+        "search",
+        "microsoft"
+      ],
       "cwd": "${workspaceFolder}/src/kiota",
       "console": "internalConsole",
       "stopAtEntry": false
@@ -207,7 +210,10 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["search", "test"],
+      "args": [
+        "search",
+        "test"
+      ],
       "cwd": "${workspaceFolder}/src/kiota",
       "console": "internalConsole",
       "stopAtEntry": false
@@ -249,7 +255,11 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["info", "-l", "CSharp"],
+      "args": [
+        "info",
+        "-l",
+        "CSharp"
+      ],
       "cwd": "${workspaceFolder}/src/kiota",
       "console": "internalConsole",
       "stopAtEntry": false
@@ -260,7 +270,11 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["update", "-o", "${workspaceFolder}/samples"],
+      "args": [
+        "update",
+        "-o",
+        "${workspaceFolder}/samples"
+      ],
       "cwd": "${workspaceFolder}/src/kiota",
       "console": "internalConsole",
       "stopAtEntry": false
@@ -271,7 +285,10 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["workspace", "migrate"],
+      "args": [
+        "workspace",
+        "migrate"
+      ],
       "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet",
       "console": "internalConsole",
       "stopAtEntry": false,
@@ -285,7 +302,10 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["client", "generate"],
+      "args": [
+        "client",
+        "generate"
+      ],
       "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet",
       "console": "internalConsole",
       "stopAtEntry": false,
@@ -330,7 +350,9 @@
         "-i",
         "**/messages",
         "--type",
-        "APIManifest"
+        "ApiManifest",
+        "--type",
+        "microsoft"
       ],
       "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet",
       "console": "internalConsole",
@@ -345,7 +367,11 @@
       "request": "launch",
       "preLaunchTask": "build",
       "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll",
-      "args": ["login", "github", "device"],
+      "args": [
+        "login",
+        "github",
+        "device"
+      ],
       "cwd": "${workspaceFolder}/src/kiota",
       "console": "internalConsole",
       "stopAtEntry": false
@@ -357,4 +383,4 @@
       "processId": "${command:pickProcess}"
     }
   ]
-}
+}
\ No newline at end of file
diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj
index faa7c7dd75..e8aebabd07 100644
--- a/src/Kiota.Builder/Kiota.Builder.csproj
+++ b/src/Kiota.Builder/Kiota.Builder.csproj
@@ -47,7 +47,7 @@
     <PackageReference Include="Microsoft.OpenApi" Version="1.6.14" />
     <PackageReference Include="Microsoft.OpenApi.ApiManifest" Version="0.5.4-preview" />
     <PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.14" />
-    <PackageReference Include="Microsoft.Plugins.Manifest" Version="0.0.1-preview" />
+    <PackageReference Include="Microsoft.Plugins.Manifest" Version="0.0.6-preview" />
     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
     <PackageReference Include="YamlDotNet" Version="15.1.2" />
     <ProjectReference Include="..\Kiota.Generated\KiotaGenerated.csproj" OutputItemType="Analyzer"
diff --git a/src/Kiota.Builder/PluginType.cs b/src/Kiota.Builder/PluginType.cs
index b0285d4747..b985a129b0 100644
--- a/src/Kiota.Builder/PluginType.cs
+++ b/src/Kiota.Builder/PluginType.cs
@@ -3,5 +3,6 @@
 public enum PluginType
 {
     OpenAI,
-    APIManifest
+    APIManifest,
+    Microsoft
 }
diff --git a/src/Kiota.Builder/Plugins/AuthComparer.cs b/src/Kiota.Builder/Plugins/AuthComparer.cs
index a38c781692..e5212d44de 100644
--- a/src/Kiota.Builder/Plugins/AuthComparer.cs
+++ b/src/Kiota.Builder/Plugins/AuthComparer.cs
@@ -16,6 +16,6 @@ public bool Equals(Auth? x, Auth? y)
     public int GetHashCode([DisallowNull] Auth obj)
     {
         if (obj == null) return 0;
-        return string.IsNullOrEmpty(obj.Type) ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Type) * 3;
+        return obj.Type is null ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Type.Value.ToString()) * 3;
     }
 }
diff --git a/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs b/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs
index 944cc78d39..fc699b070e 100644
--- a/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs
+++ b/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs
@@ -7,7 +7,7 @@
 
 namespace Kiota.Builder.Plugins;
 
-internal class OpenAPIRuntimeComparer : IEqualityComparer<OpenAPIRuntime>
+internal class OpenAPIRuntimeComparer : IEqualityComparer<OpenApiRuntime>
 {
     public bool EvaluateFunctions
     {
@@ -15,17 +15,18 @@ public bool EvaluateFunctions
     }
     private static readonly StringIEnumerableDeepComparer _stringIEnumerableDeepComparer = new();
     private static readonly AuthComparer _authComparer = new();
+    private static readonly OpenApiRuntimeSpecComparer _openApiRuntimeSpecComparer = new();
     /// <inheritdoc/>
-    public bool Equals(OpenAPIRuntime? x, OpenAPIRuntime? y)
+    public bool Equals(OpenApiRuntime? x, OpenApiRuntime? y)
     {
         return x == null && y == null || x != null && y != null && GetHashCode(x) == GetHashCode(y);
     }
     /// <inheritdoc/>
-    public int GetHashCode([DisallowNull] OpenAPIRuntime obj)
+    public int GetHashCode([DisallowNull] OpenApiRuntime obj)
     {
         if (obj == null) return 0;
         return (EvaluateFunctions ? _stringIEnumerableDeepComparer.GetHashCode(obj.RunForFunctions ?? Enumerable.Empty<string>()) * 7 : 0) +
-            obj.Spec.Select(static x => StringComparer.Ordinal.GetHashCode($"{x.Key}:{x.Value}")).Aggregate(0, (acc, next) => acc + next) * 5 +
+            (obj.Spec is null ? 0 : _openApiRuntimeSpecComparer.GetHashCode(obj.Spec) * 5) +
             (obj.Auth is null ? 0 : _authComparer.GetHashCode(obj.Auth) * 3);
     }
 }
diff --git a/src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs b/src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs
new file mode 100644
index 0000000000..38de08d0cf
--- /dev/null
+++ b/src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs
@@ -0,0 +1,23 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Microsoft.Plugins.Manifest;
+
+namespace Kiota.Builder.Plugins;
+
+public class OpenApiRuntimeSpecComparer : IEqualityComparer<OpenApiRuntimeSpec>
+{
+    /// <inheritdoc/>
+    public bool Equals(OpenApiRuntimeSpec? x, OpenApiRuntimeSpec? y)
+    {
+        return x == null && y == null || x != null && y != null && GetHashCode(x) == GetHashCode(y);
+    }
+    /// <inheritdoc/>
+    public int GetHashCode([DisallowNull] OpenApiRuntimeSpec obj)
+    {
+        if (obj == null) return 0;
+        return (string.IsNullOrEmpty(obj.Url) ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Url) * 5) +
+               (string.IsNullOrEmpty(obj.ApiDescription) ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.ApiDescription) * 3);
+    }
+}
diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs
index bc0c3e4bf7..09f073b182 100644
--- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs
+++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs
@@ -8,6 +8,8 @@
 using Kiota.Builder.Configuration;
 using Kiota.Builder.Extensions;
 using Kiota.Builder.OpenApiExtensions;
+using Microsoft.Kiota.Abstractions.Extensions;
+using Microsoft.OpenApi.ApiManifest;
 using Microsoft.OpenApi.Models;
 using Microsoft.OpenApi.Services;
 using Microsoft.OpenApi.Writers;
@@ -30,31 +32,52 @@ public PluginsGenerationService(OpenApiDocument document, OpenApiUrlTreeNode ope
         Configuration = configuration;
     }
     private static readonly OpenAPIRuntimeComparer _openAPIRuntimeComparer = new();
-    private const string ManifestFileName = "manifest.json";
+    private const string ManifestFileNameSuffix = ".json";
     private const string DescriptionRelativePath = "./openapi.yml";
     public async Task GenerateManifestAsync(CancellationToken cancellationToken = default)
     {
-        var manifestOutputPath = Path.Combine(Configuration.OutputPath, ManifestFileName);
-        var directory = Path.GetDirectoryName(manifestOutputPath);
+        // write the decription
+        var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath);
+        var directory = Path.GetDirectoryName(descriptionFullPath);
         if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
             Directory.CreateDirectory(directory);
-
-        var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath);
 #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
         await using var descriptionStream = File.Create(descriptionFullPath, 4096);
         await using var fileWriter = new StreamWriter(descriptionStream);
+#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
         var descriptionWriter = new OpenApiYamlWriter(fileWriter);
         OAIDocument.SerializeAsV3(descriptionWriter);
         descriptionWriter.Flush();
 
-        var pluginDocument = GetManifestDocument(DescriptionRelativePath);
-        await using var fileStream = File.Create(manifestOutputPath, 4096);
-        await using var writer = new Utf8JsonWriter(fileStream, new JsonWriterOptions { Indented = true });
+        // write the plugins
+        foreach (var pluginType in Configuration.PluginTypes)
+        {
+            var manifestOutputPath = Path.Combine(Configuration.OutputPath, $"{Configuration.ClientClassName.ToLowerInvariant()}-{pluginType.ToString().ToLowerInvariant()}{ManifestFileNameSuffix}");
+#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
+            await using var fileStream = File.Create(manifestOutputPath, 4096);
+            await using var writer = new Utf8JsonWriter(fileStream, new JsonWriterOptions { Indented = true });
 #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
-        pluginDocument.Write(writer);
-        await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
+
+            switch (pluginType)
+            {
+                case PluginType.Microsoft:
+                    var pluginDocument = GetManifestDocument(DescriptionRelativePath);
+                    pluginDocument.Write(writer);
+                    break;
+                case PluginType.APIManifest:
+                    var apiManifest = new ApiManifestDocument("application"); //TODO add application name
+                    apiManifest.ApiDependencies.AddOrReplace(Configuration.ClientClassName, Configuration.ToApiDependency(OAIDocument.HashCode ?? string.Empty, TreeNode?.GetRequestInfo().ToDictionary(static x => x.Key, static x => x.Value) ?? []));
+                    apiManifest.Write(writer);
+                    break;
+                case PluginType.OpenAI://TODO add support for OpenAI plugin type generation
+                                       // intentional drop to the default case
+                default:
+                    throw new NotImplementedException($"The {pluginType} plugin is not implemented.");
+            }
+            await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
+        }
     }
-    private ManifestDocument GetManifestDocument(string openApiDocumentPath)
+    private PluginManifestDocument GetManifestDocument(string openApiDocumentPath)
     {
         var (runtimes, functions) = GetRuntimesAndFunctionsFromTree(TreeNode, openApiDocumentPath);
         var descriptionForHuman = OAIDocument.Info?.Description.CleanupXMLString() is string d && !string.IsNullOrEmpty(d) ? d : $"Description for {OAIDocument.Info?.Title.CleanupXMLString()}";
@@ -64,7 +87,6 @@ private ManifestDocument GetManifestDocument(string openApiDocumentPath)
         string? privacyUrl = null;
         if (OAIDocument.Info is not null)
         {
-
             if (OAIDocument.Info.Extensions.TryGetValue(OpenApiDescriptionForModelExtension.Name, out var descriptionExtension) &&
                 descriptionExtension is OpenApiDescriptionForModelExtension extension &&
                 !string.IsNullOrEmpty(extension.Description))
@@ -76,7 +98,7 @@ descriptionExtension is OpenApiDescriptionForModelExtension extension &&
             if (OAIDocument.Info.Extensions.TryGetValue(OpenApiPrivacyPolicyUrlExtension.Name, out var privacyExtension) && privacyExtension is OpenApiPrivacyPolicyUrlExtension privacy)
                 privacyUrl = privacy.Privacy;
         }
-        return new ManifestDocument
+        return new PluginManifestDocument
         {
             SchemaVersion = "v2",
             NameForHuman = OAIDocument.Info?.Title.CleanupXMLString(),
@@ -100,18 +122,21 @@ descriptionExtension is OpenApiDescriptionForModelExtension extension &&
             Functions = [.. functions.OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)]
         };
     }
-    private (OpenAPIRuntime[], Function[]) GetRuntimesAndFunctionsFromTree(OpenApiUrlTreeNode currentNode, string openApiDocumentPath)
+    private (OpenApiRuntime[], Function[]) GetRuntimesAndFunctionsFromTree(OpenApiUrlTreeNode currentNode, string openApiDocumentPath)
     {
-        var runtimes = new List<OpenAPIRuntime>();
+        var runtimes = new List<OpenApiRuntime>();
         var functions = new List<Function>();
         if (currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem))
         {
             foreach (var operation in pathItem.Operations.Values.Where(static x => !string.IsNullOrEmpty(x.OperationId)))
             {
-                runtimes.Add(new OpenAPIRuntime
+                runtimes.Add(new OpenApiRuntime
                 {
-                    Auth = new Auth("none"),
-                    Spec = new Dictionary<string, string> { { "url", openApiDocumentPath } },
+                    Auth = new AnonymousAuth(),
+                    Spec = new OpenApiRuntimeSpec()
+                    {
+                        Url = openApiDocumentPath
+                    },
                     RunForFunctions = [operation.OperationId]
                 });
                 var oasParameters = operation.Parameters
@@ -123,19 +148,26 @@ descriptionExtension is OpenApiDescriptionForModelExtension extension &&
                 functions.Add(new Function
                 {
                     Name = operation.OperationId,
-                    Description = operation.Summary.CleanupXMLString() is string summary && !string.IsNullOrEmpty(summary) ? summary : operation.Description.CleanupXMLString(),
-                    Parameters = oasParameters.Length == 0 ? null :
-                                    new Parameters(
-                                        "object",
-                                        new Properties(oasParameters.ToDictionary(
-                                                                        static x => x.Name,
-                                                                        static x => new Property(
-                                                                                        x.Schema.Type ?? string.Empty,
-                                                                                        x.Description.CleanupXMLString(),
-                                                                                        x.Schema.Default?.ToString() ?? string.Empty,
-                                                                                        null), //TODO enums
-                                                                        StringComparer.OrdinalIgnoreCase)),
-                                        oasParameters.Where(static x => x.Required).Select(static x => x.Name).ToList()),
+                    Description =
+                        operation.Summary.CleanupXMLString() is string summary && !string.IsNullOrEmpty(summary)
+                            ? summary
+                            : operation.Description.CleanupXMLString(),
+                    Parameters = oasParameters.Length == 0
+                        ? null
+                        : new Parameters
+                        {
+                            Type = "object",
+                            Properties = new Properties(oasParameters.ToDictionary(
+                                static x => x.Name,
+                                static x => new FunctionParameter()
+                                {
+                                    Type = x.Schema.Type ?? string.Empty,
+                                    Description = x.Description.CleanupXMLString(),
+                                    Default = x.Schema.Default?.ToString() ?? string.Empty,
+                                    //TODO enums
+                                })),
+                            Required = oasParameters.Where(static x => x.Required).Select(static x => x.Name).ToList()
+                        },
                     States = GetStatesFromOperation(operation),
                 });
             }
@@ -177,7 +209,7 @@ rExtRaw is T rExt &&
         {
             return new State
             {
-                Instructions = instructionsExtractor(rExt).Where(static x => !string.IsNullOrEmpty(x)).Select(static x => x.CleanupXMLString()).ToList()
+                Instructions = new Instructions(instructionsExtractor(rExt).Where(static x => !string.IsNullOrEmpty(x)).Select(static x => x.CleanupXMLString()).ToList())
             };
         }
         return null;
diff --git a/src/kiota/Handlers/Plugin/AddHandler.cs b/src/kiota/Handlers/Plugin/AddHandler.cs
index 2f150fcd82..be662926cd 100644
--- a/src/kiota/Handlers/Plugin/AddHandler.cs
+++ b/src/kiota/Handlers/Plugin/AddHandler.cs
@@ -94,6 +94,5 @@ public override async Task<int> InvokeAsync(InvocationContext context)
 #endif
             }
         }
-        throw new NotImplementedException();
     }
 }
diff --git a/src/kiota/kiota.csproj b/src/kiota/kiota.csproj
index bd261b9694..68e3fec832 100644
--- a/src/kiota/kiota.csproj
+++ b/src/kiota/kiota.csproj
@@ -46,7 +46,7 @@
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
     <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
     <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
-    <PackageReference Include="Microsoft.OpenApi.ApiManifest" Version="0.5.4-preview" />
+    <PackageReference Include="Microsoft.OpenApi.ApiManifest" Version="0.5.5-preview" />
     <PackageReference Include="StreamJsonRpc" Version="2.17.11" />
     <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />


Test patch:
diff --git a/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs b/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs
index 936f073ac3..97808aa1c9 100644
--- a/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs
+++ b/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs
@@ -17,8 +17,8 @@ public void Defensive()
     [Fact]
     public void GetsHashCode()
     {
-        var runtime1 = new OpenAPIRuntime { Spec = new() { { "key1", "value1" } } };
-        var runtime2 = new OpenAPIRuntime { Spec = new() { { "key2", "value2" } }, Auth = new() { Type = "type" } };
+        var runtime1 = new OpenApiRuntime { Spec = new() { Url = "url", ApiDescription = "description" } };
+        var runtime2 = new OpenApiRuntime { Spec = new() { Url = "url", ApiDescription = "description" }, Auth = new AnonymousAuth() };
         Assert.NotEqual(_comparer.GetHashCode(runtime1), _comparer.GetHashCode(runtime2));
     }
 }
diff --git a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs
index 83baa0ba06..77e2b4a638 100644
--- a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs
+++ b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs
@@ -33,6 +33,9 @@ public async Task GeneratesManifest()
 info:
   title: test
   version: 1.0
+servers:
+  - url: http://localhost/
+    description: There's no place like home
 paths:
   /test:
     get:
@@ -49,8 +52,9 @@ public async Task GeneratesManifest()
         {
             OutputPath = outputDirectory,
             OpenAPIFilePath = "openapiPath",
-            PluginTypes = [PluginType.APIManifest],
+            PluginTypes = [PluginType.Microsoft, PluginType.APIManifest],
             ClientClassName = "client",
+            ApiRootUrl = "http://localhost/", //Kiota builder would set this for us
         };
         var (openAPIDocumentStream, _) = await openAPIDocumentDS.LoadStreamAsync(simpleDescriptionPath, generationConfiguration, null, false);
         var openApiDocument = await openAPIDocumentDS.GetDocumentFromStreamAsync(openAPIDocumentStream, generationConfiguration);
@@ -59,7 +63,8 @@ public async Task GeneratesManifest()
         var pluginsGenerationService = new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration);
         await pluginsGenerationService.GenerateManifestAsync();
 
-        Assert.True(File.Exists(Path.Combine(outputDirectory, "manifest.json")));
+        Assert.True(File.Exists(Path.Combine(outputDirectory, "client-microsoft.json")));
+        Assert.True(File.Exists(Path.Combine(outputDirectory, "client-apimanifest.json")));
         Assert.True(File.Exists(Path.Combine(outputDirectory, "openapi.yml")));
     }
 }