-
Notifications
You must be signed in to change notification settings - Fork 17
Extract CLI skills into dedicated project #188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| using System.Reflection; | ||
|
|
||
| namespace Microsoft.Maui.Cli.Skills; | ||
|
|
||
| public static class MauiCliSkillResources | ||
| { | ||
| public const string ResourceRoot = "devflow.skills"; | ||
|
|
||
| public static Assembly Assembly => typeof(MauiCliSkillResources).Assembly; | ||
|
|
||
| public static IReadOnlyList<MauiCliSkillDefinition> BundledSkills { get; } = | ||
| [ | ||
| new("maui-devflow-onboard", "MAUI DevFlow Onboard", "Guides first-time MAUI DevFlow project integration.", Recommended: true), | ||
| new("maui-devflow-debug", "MAUI DevFlow Debug", "Guides build, deploy, connection recovery, inspect, and debug loops with MAUI DevFlow.", Recommended: true) | ||
| ]; | ||
| } | ||
|
|
||
| public sealed record MauiCliSkillDefinition(string Id, string DisplayName, string Description, bool Recommended); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFrameworks>net9.0;net10.0</TargetFrameworks> | ||
| <RootNamespace>Microsoft.Maui.Cli.Skills</RootNamespace> | ||
| <AssemblyName>Microsoft.Maui.Cli.Skills</AssemblyName> | ||
| <Description>Bundled agent skills for the .NET MAUI CLI</Description> | ||
| <IsPackable>false</IsPackable> | ||
| <IsAotCompatible>true</IsAotCompatible> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <EmbeddedResource Include="..\..\..\plugins\dotnet-maui\skills\maui-devflow-onboard\**\*" LogicalName="devflow.skills/maui-devflow-onboard/%(RecursiveDir)%(Filename)%(Extension)"> | ||
| <WithCulture>false</WithCulture> | ||
| </EmbeddedResource> | ||
| <EmbeddedResource Include="..\..\..\plugins\dotnet-maui\skills\maui-devflow-debug\**\*" LogicalName="devflow.skills/maui-devflow-debug/%(RecursiveDir)%(Filename)%(Extension)"> | ||
| <WithCulture>false</WithCulture> | ||
| </EmbeddedResource> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,12 +3,13 @@ | |
| using System.Text; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Nodes; | ||
| using Microsoft.Maui.Cli.Skills; | ||
|
|
||
| namespace Microsoft.Maui.Cli.DevFlow.Skills; | ||
|
|
||
| internal static class DevFlowSkillManager | ||
| { | ||
| const string ResourceRoot = "devflow.skills"; | ||
| const string ResourceRoot = MauiCliSkillResources.ResourceRoot; | ||
| const string PackageId = "Microsoft.Maui.Cli"; | ||
| const string StateRootEnvironmentVariable = "MAUIDEVFLOW_STATE_ROOT"; | ||
| const string AutoTarget = "auto"; | ||
|
|
@@ -19,11 +20,9 @@ internal static class DevFlowSkillManager | |
| static readonly TimeSpan FreshnessCheckInterval = TimeSpan.FromDays(7); | ||
| static readonly TimeSpan FreshnessPromptInterval = TimeSpan.FromDays(1); | ||
|
|
||
| static readonly DevFlowSkillDefinition[] s_skills = | ||
| [ | ||
| new("maui-devflow-onboard", "MAUI DevFlow Onboard", "Guides first-time MAUI DevFlow project integration.", Recommended: true), | ||
| new("maui-devflow-debug", "MAUI DevFlow Debug", "Guides build, deploy, connection recovery, inspect, and debug loops with MAUI DevFlow.", Recommended: true) | ||
| ]; | ||
| static readonly DevFlowSkillDefinition[] s_skills = MauiCliSkillResources.BundledSkills | ||
| .Select(skill => new DevFlowSkillDefinition(skill.Id, skill.DisplayName, skill.Description, skill.Recommended)) | ||
| .ToArray(); | ||
|
|
||
| static readonly string[] s_legacySkillIds = | ||
| [ | ||
|
|
@@ -463,7 +462,7 @@ static bool MigrateLegacySkills(InstallTarget installTarget, JsonObject skillSta | |
|
|
||
| static async Task<SkillBundle> LoadSkillBundleAsync(DevFlowSkillDefinition skill, CancellationToken cancellationToken) | ||
| { | ||
| var assembly = typeof(DevFlowSkillManager).Assembly; | ||
| var assembly = MauiCliSkillResources.Assembly; | ||
| var prefix = $"{ResourceRoot}/{skill.Id}/"; | ||
| var resources = assembly.GetManifestResourceNames() | ||
| .Where(name => name.StartsWith(prefix, StringComparison.Ordinal)) | ||
|
|
@@ -488,7 +487,7 @@ static async Task<SkillBundle> LoadSkillBundleAsync(DevFlowSkillDefinition skill | |
| files.Add(new SkillAssetFile(relativePath, content, HashContent(content))); | ||
| } | ||
|
|
||
| return new SkillBundle(skill.Id, GetCurrentCliVersion(), files, HashBundle(files)); | ||
| return new SkillBundle(skill.Id, GetBundledSkillVersion(), files, HashBundle(files)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 MODERATE · consensus 2/3 Version decoupling incomplete — update safety logic still coupled to CLI version. This line correctly records Recommendation: Write |
||
| } | ||
|
|
||
| static bool ShouldExcludeSkillAsset(string relativePath) | ||
|
|
@@ -1144,6 +1143,12 @@ static string GetCurrentCliVersion() | |
| ?? typeof(DevFlowSkillManager).Assembly.GetName().Version?.ToString() | ||
| ?? "unknown"; | ||
|
|
||
| static string GetBundledSkillVersion() | ||
| => MauiCliSkillResources.Assembly | ||
| .GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion | ||
| ?? MauiCliSkillResources.Assembly.GetName().Version?.ToString() | ||
| ?? GetCurrentCliVersion(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟢 MINOR · consensus 2/3 Fallback to If the Skills assembly has no Recommendation: Consider using |
||
|
|
||
| static string? GetString(JsonObject node, string propertyName) | ||
| => node.TryGetPropertyValue(propertyName, out var value) ? value?.GetValue<string>() : null; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MODERATE · consensus 3/3
Silent failure if
BundledSkillslist and.csprojembedded resource globs diverge.These two manually-maintained lists must stay in sync: the
BundledSkillsentries here and theEmbeddedResourceincludes in the.csproj. If a future skill directory is added to the.csprojglob but not to this list (or vice versa):BundledSkills→ resources are embedded but never discovered (silent dead weight).csproj→LoadSkillBundleAsyncfinds zero resources and throwsInvalidOperationException("No embedded DevFlow skill resources found...")at runtimeThe existing unit test hardcodes the two known skill names and wouldn't catch divergence when a third skill is added.
Recommendation: Add a test (or adjust the existing one) that dynamically iterates
MauiCliSkillResources.BundledSkillsand asserts each entry has at least one embedded resource with prefix{ResourceRoot}/{skill.Id}/, and conversely that every embedded resource prefix maps to aBundledSkillsentry.