feat: add maui devflow init onboarding command#146
Conversation
Add 'maui devflow init' command that onboards MAUI projects for DevFlow: - Shipped versioned manifest (devflow-init-manifest.json) - MSBuild-based project evaluation via Microsoft.Build APIs with XML fallback - Roslyn-based MauiProgram.cs patching for agent registration - Central Package Management detection and Directory.Packages.props updates - AI host bootstrap (Claude/Copilot skill sync, marketplace install) - Workspace-level MAUI-DEVFLOW-INIT-REPORT.md generation - devflow-onboard skill for AI-driven onboarding orchestration MSBuild integration uses the two-method NoInlining pattern to ensure MSBuildLocator registers its assembly resolver before any Microsoft.Build types are JIT-resolved. EvaluatedProject extracts all data upfront into a pure DTO with zero Microsoft.Build type references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- GTK/Linux: scanner now marks GTK projects as supported with 'gtk' and 'gtk-blazor' flavors. Updater selects Agent.Gtk/Blazor.Gtk packages. MauiProgramPatcher uses GTK namespaces for using directives. - Manifest: added agentGtk and blazorGtk package entries. - --gtk option: force GTK package selection via CLI flag. - --new option: scaffold a new MAUI project (maui/maui-blazor) with dotnet new before running onboarding. --name/-n sets the project name. - Tests: 9 new tests covering GTK detection, GTK Blazor, GTK patcher namespaces, already-onboarded idempotency, Blazor E2E flow, empty workspace, and manifest GTK packages. 334 total tests, all passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Write MAUI-DEVFLOW-INIT-REPORT.json alongside .md for AI-parseable reporting - Add source-gen JsonSerializerContext for DevFlowInitReport - Add --force option to re-apply onboarding on already-integrated projects - Add NextSteps to report model with context-aware suggestions - Add VerificationCommands per-project (dotnet build, maui devflow wait, etc.) - Already-onboarded projects show verification commands and --force hint - Enhanced manual-step messages with copy-pasteable code snippets - Human summary now shows JSON report path and next steps - 4 new tests: JSON sidecar, --force, NextSteps, VerificationCommands - All 18 DevFlow init tests pass (337 total, 1 pre-existing Android SDK failure) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Expert Code Review — maui devflow init (PR #146)
Methodology: 3 independent reviewers with adversarial consensus. Findings required agreement from ≥2 reviewers; disputed single-reviewer findings went through targeted tiebreaker review.
Findings Summary
| # | Severity | File | Consensus | Finding |
|---|---|---|---|---|
| 1 | 🔴 CRITICAL | GitHubDirectorySync.cs:102 |
2/3 reviewers | Path traversal via untrusted GitHub API response — filenames from the API are used in Path.Combine without validation, enabling writes outside the destination root |
| 2 | 🟡 MODERATE | DevFlowInitCommand.cs:512–527 |
2/3 reviewers | Argument injection and path traversal via --name — unsanitized project name enables workspace escape and Windows argument splitting |
| 3 | 🟡 MODERATE | MsBuildEnvironment.cs:22–34 |
2/3 reviewers | Race condition in EnsureRegistered — concurrent threads can poison s_state even when registration succeeds |
| 4 | 🟡 MODERATE | DevFlowInitCommand.cs:118–125 |
2/3 reviewers | Duplicate project entry in report — --project on an already-integrated project creates two contradictory entries |
| 5 | 🟡 MODERATE | DevFlowInitCommand.cs:34 |
2/3 reviewers | CancellationToken not propagated — Ctrl+C cannot cancel long operations (process spawn, HTTP, MSBuild eval) |
| 6 | 🟡 MODERATE | DevFlowProjectUpdater.cs:133–142 |
3/3 reviewers (after tiebreak) | FindDirectoryPackagesProps walks past workspace root — can discover and modify an unrelated Directory.Packages.props |
Discarded Findings (single-reviewer only)
These were flagged by only 1 of 3 reviewers and either failed tiebreak or were below the tiebreak cap:
- Supply chain risk from mutable
mainref in skill sync (1/3 → tiebreak: 0/2 agreed — both noted same trust boundary as the CLI itself) GlobalProjectCollectionthread-safety inMsBuildProjectMutator(1/3 → tiebreak: 0/2 agreed — calls are sequential, not concurrent)- No GitHub API authentication / rate limiting (1/3, no tiebreak)
Processobject not disposed inScaffoldNewProjectAsync(1/3, no tiebreak)- CPM detection false positive when project opts out (1/3, no tiebreak)
- Partial AI bootstrap failure treated as full command failure (1/3, no tiebreak)
- Double MSBuild evaluation in
DetectCentralPackageManagement(1/3, no tiebreak) - GitHub API URL parameters not URL-encoded (1/3, no tiebreak)
EnsureUsingmay miss usings inside#if DEBUGblocks (1/3, no tiebreak)- Symlink cycle risk in
DevFlowProjectScanner.Discover(1/3, no tiebreak) MauiProgramPatcherdoesn't preserve file encoding/BOM (1/3, no tiebreak)
CI Status
At review time, CI builds (macOS, Windows, Ubuntu) were still in progress. CLA check passed ✅. Test coverage: 18 unit tests covering manifest loading, project scanning, Roslyn patching, CPM updates, GTK support, and end-to-end flows.
Overall Assessment
Well-structured PR with clean separation of concerns (pipeline pattern, testable stages). The two security findings (#1, #2) should be addressed before merge — both involve untrusted input flowing into filesystem paths without validation. The race condition (#3) and missing cancellation (#5) are worth fixing for robustness. The duplicate report entry (#4) and unbounded directory walk (#6) are correctness issues that affect user experience.
Generated by Expert Code Review (auto) for issue #146 · ● 16.2M
|
I also proposed #98 although this one is of course more specific, they might have some overlap |
|
Good call -- there is definitely overlap with #98. This PR focuses specifically on the |
There was a problem hiding this comment.
Pull request overview
Adds a new maui devflow init command to automate DevFlow onboarding for existing (or newly scaffolded) MAUI projects, including project discovery, package/CPM updates, MauiProgram patching, optional AI-host bootstrap, and report generation.
Changes:
- Introduces an init pipeline under
src/Cli/Microsoft.Maui.Cli/DevFlow/Init/(MSBuild evaluation/mutation + Roslyn patching + reporting). - Wires the new
devflow initsubcommand into the CLI and updates docs/skills to promote the new onboarding flow. - Adds unit tests and supporting manifest/config assets (embedded manifest + skill/eval scenarios).
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/dotnet-maui/devflow-onboard/eval.yaml | Adds evaluation scenarios asserting agents recommend maui devflow init and follow the init report. |
| src/DevFlow/README.md | Documents recommended onboarding via maui devflow init. |
| src/Cli/Microsoft.Maui.Cli/Program.cs | Adds trimming/AOT annotations and warning suppression around root command construction. |
| src/Cli/Microsoft.Maui.Cli/Microsoft.Maui.Cli.csproj | Adds MSBuild/Roslyn dependencies and embeds the init manifest resource. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/devflow-init-manifest.json | Defines package IDs/versions and AI host bootstrap configuration as an embedded manifest. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/MsBuildProjectEvaluator.cs | Implements MSBuild project evaluation snapshot + format-preserving csproj/props mutation helpers. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/MsBuildEnvironment.cs | Adds MSBuildLocator registration helper for safe MSBuild API loading. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/MauiProgramPatcher.cs | Implements Roslyn-based patching of MauiProgram.cs to add DevFlow registration/usings. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/GitHubDirectorySync.cs | Adds GitHub directory listing + raw file sync for repo-local skill fallback. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/DevFlowProjectUpdater.cs | Orchestrates package/CPM updates and MauiProgram patching per project. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/DevFlowProjectScanner.cs | Discovers MAUI projects via MSBuild evaluation with XML fallback and infers project flavor. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/DevFlowInitModels.cs | Adds init report/operation models and JSON source-gen context. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/DevFlowInitManifest.cs | Adds manifest model + embedded-resource loader with source-gen deserialization. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/DevFlowInitCommand.cs | Implements the init command flow and writes markdown + JSON reports. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/Init/AiHostBootstrapper.cs | Adds AI host detection/selection and repo-local skill sync bootstrap logic. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/DevFlowCommands.cs | Registers the new devflow init command and options in the CLI. |
| src/Cli/Microsoft.Maui.Cli.UnitTests/DevFlowInitTests.cs | Adds unit tests covering manifest loading, scanning, patching, CPM updates, and init flows. |
| src/Cli/Microsoft.Maui.Cli.UnitTests/CommandConstructionTests.cs | Ensures the init subcommand is present in the DevFlow command tree. |
| plugins/dotnet-maui/skills/devflow-onboard/SKILL.md | Adds a new onboarding skill centered on maui devflow init + report-driven follow-up. |
| plugins/dotnet-maui/skills/devflow-connect/SKILL.md | Updates connection troubleshooting guidance to use builder.AddMauiDevFlowAgent(). |
| plugins/README.md | Updates plugin catalog to include devflow-onboard. |
| eng/Versions.props | Adds version properties for Roslyn/MSBuild dependencies. |
| README.md | Updates top-level plugin install instructions with onboarding prompt suggestion. |
| Directory.Packages.props | Adds centrally managed package versions for Roslyn/MSBuild dependencies. |
| .claude/skills/maui-ai-debugging/references/setup.md | Updates docs to correct DevFlow namespace references. |
| .claude/skills/maui-ai-debugging/references/macos.md | Updates docs to correct DevFlow namespace references. |
| .claude/skills/maui-ai-debugging/references/linux.md | Updates docs to correct DevFlow namespace references. |
- Path traversal guard in GitHubDirectorySync (validates dest stays in root) - Lock-based thread safety in MsBuildEnvironment.EnsureRegistered - Regex validation + ArgumentList for --name to prevent injection - Dedup guard for already-present projects in report - Bounded FindDirectoryPackagesProps walk to workspace root - CancellationToken propagated through ExecuteAsync, SyncAsync, and helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When CPM is active and a PackageReference already exists with an inline Version attribute, the mutator now strips it so CPM controls the version via Directory.Packages.props. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Multi-line manual steps (with embedded code blocks) were emitted as single-line list items, breaking markdown rendering. Added AppendListItem helper that indents continuation lines with 4 spaces so fenced code blocks and multi-line content render correctly inside list items. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wrap GitHubDirectorySync.SyncAsync in try/catch so network errors, rate limiting, or 404s during repo-local skill sync degrade to ManualRequired status with retry guidance instead of aborting the entire init flow. OperationCanceledException is re-thrown to respect cancellation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WriteReportAsync now accepts a dryRun flag and returns early without writing MAUI-DEVFLOW-INIT-REPORT.md or .json to disk when true. The report is still passed to output.WriteResult so the user sees the result in stdout/JSON output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Expert Code Review — maui devflow init onboarding command
Methodology: 3 independent reviewers with adversarial consensus. Findings flagged by only 1 reviewer were escalated to tiebreakers; only issues confirmed by 2+ reviewers are included.
Findings by Severity
| # | Severity | File | Finding | Consensus |
|---|---|---|---|---|
| 1 | 🔴 CRITICAL | DevFlowInitCommand.cs:585 |
Sequential stdout/stderr ReadToEndAsync can deadlock on large output |
2/3 reviewers |
| 2 | 🟡 MODERATE | DevFlowInitCommand.cs:375 |
WriteReportAsync ignores --dry-run — writes report files even in dry-run mode |
3/3 reviewers |
| 3 | 🟡 MODERATE | DevFlowInitCommand.cs:188 |
WriteReportAsync in catch blocks can mask the original exception with an I/O error |
3/3 reviewers |
| 4 | 🟡 MODERATE | DevFlowProjectUpdater.cs:130 |
CPM detection returns false positive when ManagePackageVersionsCentrally is explicitly false |
3/3 reviewers |
| 5 | 🟡 MODERATE | GitHubDirectorySync.cs:40 |
No timeout, rate-limit handling, or optional auth for GitHub API calls | 2/3 reviewers |
✅ Issues Already Addressed in Latest Push
The following issues were flagged by reviewers against the initial diff but have already been resolved in the current PR head:
- Path traversal in
GitHubDirectorySync.SyncAsync— now guarded withPath.GetFullPath+StartsWithcheck - Race condition in
MsBuildEnvironment.EnsureInitializedAsync— now useslock (s_lock) - Argument injection via
--nameinScaffoldNewProjectAsync— now validates with regex (^[A-Za-z0-9._-]+$) and usesProcessStartInfo.ArgumentListAPI FindDirectoryPackagesPropswalking past workspace root — now bounded byworkspaceRootparameter
Great work addressing these proactively. 👍
Discarded Findings (single reviewer only, not confirmed)
- Sync overwrites local files without user confirmation prompt
Processnot disposed inScaffoldNewProjectAsync- UTF-8 BOM stripping assumption in
MauiProgramPatcher - Overly broad Copilot host detection marker matching
CI Status
CI builds are in progress at time of review (macOS, Windows, Ubuntu matrix). check job completed ✅; evaluate and gate skipped. No test failures observed yet.
Generated by Expert Code Review (auto) for issue #146 · ● 20.1M
…utput The --json flag on devflow init crashed because DevFlowInitReport was registered in its own report-file JsonContext but not in the CLI's DevFlowCliJsonContext used by output.WriteResult. Add the missing [JsonSerializable] attribute. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use Span.End (not FullSpan.End) for using insertion so trailing trivia (blank lines before namespace) is preserved - Detect file's existing line endings and use them consistently instead of Environment.NewLine (fixes mixed \r\n / \n) - Put #if DEBUG / #endif at column 0 (standard C# convention) - Insert registration block at line start instead of SpanStart so return statement keeps its original indentation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three fixes: 1. ResolveAgentPort() no longer auto-starts the broker daemon. It only checks existing broker state and config files. Commands that need the broker already call EnsureBrokerRunningAsync() themselves. This eliminates noisy stderr errors on commands like 'init' that don't use the broker. 2. DetermineOverallStatus() no longer lets AI bootstrap failures override project-level success. When all projects are 'already_present' or 'success', the overall status reflects that. AI issues are surfaced in the next-steps section instead. 3. BrokerClient.IsBrokerAliveAsync changed from private to internal so ResolveAgentPort can check liveness without triggering auto-start. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ReadConfigPort() calls Directory.GetCurrentDirectory() which throws FileNotFoundException when the CWD no longer exists (e.g. deleted temp dirs). Wrap the call in try/catch and remove the duplicate unguarded call in the fallback path of ResolveAgentPort(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- CRITICAL: Read stdout/stderr concurrently to avoid deadlock when OS pipe buffers fill during dotnet new scaffolding - MODERATE: Wrap WriteReportAsync in try/catch in error handlers so I/O failures don't mask the original exception - MODERATE: Respect explicit ManagePackageVersionsCentrally=false instead of returning a false positive for CPM detection - MODERATE: Add 30s timeout and optional GITHUB_TOKEN/GH_TOKEN auth to GitHubDirectorySync HTTP client Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Directory.GetCurrentDirectory() throws FileNotFoundException when the shell's CWD was deleted and recreated (stale inode). Show a helpful error message instead of an unhandled exception. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace MSBuild Locator and Microsoft.Build NuGet packages with simple `dotnet msbuild -getProperty/-getItem` and `dotnet add package` CLI calls. This eliminates the JIT NoInlining workaround, DOTNET_ROOT auto-detection issues, and ~385 lines of infrastructure code. - Add DotnetCliProjectReader for project evaluation via dotnet CLI - Rewrite DevFlowProjectScanner to use DotnetCliProjectReader - Rewrite DevFlowProjectUpdater to use `dotnet add package --no-restore` with CPM post-processing for Directory.Packages.props - Remove MsBuildEnvironment.cs and MsBuildProjectEvaluator.cs - Remove 4 Microsoft.Build PackageReference/PackageVersion entries - Remove RequiresUnreferencedCode/RequiresDynamicCode attributes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Closed in favour of #164 |
Motivation
Getting started with MAUI DevFlow today requires several manual steps: installing the CLI tool, adding NuGet package references, patching
MauiProgram.cswith registration code, and configuring AI host skills. This PR adds a singlemaui devflow initcommand that automates the entire onboarding flow, making it possible to go from zero to a working DevFlow setup in one step.Approach
The init subsystem is built as a pipeline: discover projects -> select targets -> update csproj/CPM -> patch MauiProgram.cs -> bootstrap AI host -> generate report. Each stage is a separate, testable class under
src/Cli/Microsoft.Maui.Cli/DevFlow/Init/.Key design decisions:
MSBuild evaluation over XML parsing -- Uses
Microsoft.Build+Microsoft.Build.Locatorto properly resolve PackageReferences that may live in imported.props/.targetsfiles. AProjectViewabstraction provides XML fallback when MSBuild evaluation is unavailable. The JIT-safe[NoInlining]two-method pattern prevents assembly loading failures before MSBuildLocator registers.Roslyn-based C# patching --
MauiProgramPatcherusesMicrosoft.CodeAnalysis.CSharpto parse and transformMauiProgram.cs, inserting#if DEBUGregistration blocks and requiredusingdirectives. This is much more reliable than regex/text manipulation.Embedded manifest --
devflow-init-manifest.jsonships as an embedded resource containing package IDs, versions, and AI host configurations. This is the single source of truth for what gets installed.Format-preserving writes --
MsBuildProjectMutatorusesProjectRootElementwithpreserveFormatting: trueso csproj edits don't reformat the entire file.Features
maui devflow init-- discovers and onboards MAUI projects in the current workspace--project <path>-- target a specific project--all-- onboard all eligible projects at once--blazor/--no-blazor-- force or skip Blazor integration--gtk-- use GTK/Linux packages (Agent.Gtk,Blazor.Gtk)--new <template>/--name <n>-- scaffold a new project before onboarding--force-- re-apply onboarding on already-integrated projects (e.g. to update package versions)--no-ai/--ai-host <id>/--ai-local-only-- control AI host bootstrap--dry-run-- preview changes without writing filesMAUI-DEVFLOW-INIT-REPORT.md(human-readable) +.json(AI-parseable)NextStepsand per-projectVerificationCommandsin the reportdevflow-onboardAI skill + eval scenarios for agent-driven onboardingFiles added
DevFlowInitCommand.csDevFlowInitModels.csDevFlowInitManifest.csDevFlowProjectScanner.csDevFlowProjectUpdater.csMauiProgramPatcher.csMauiProgram.cspatchingMsBuildEnvironment.csMsBuildProjectEvaluator.csEvaluatedProject+MsBuildProjectMutatorAiHostBootstrapper.csGitHubDirectorySync.csdevflow-init-manifest.jsondevflow-onboard/SKILL.mdTesting
18 unit tests covering manifest loading, project scanning, Roslyn patching, CPM updates, GTK support, end-to-end flows (standard, Blazor, GTK, already-onboarded, empty workspace,
--force), JSON sidecar output, and next-steps population. All pass. The one pre-existingAndroidCommandsTestsfailure is unrelated.Notes
vsblob.vsassets.io(Azure DevOps blob storage), so fulldotnet restore/ Arcade builds may not work in sandbox -- CI validation needed.Microsoft.Buildpackages useExcludeAssets="runtime"so the tool loads MSBuild from the host SDK via Locator rather than shipping its own copy.