Skip to content

Add .csproj "project mode" to winapp run#612

Draft
nmetulev wants to merge 12 commits into
mainfrom
nmetulev-run-csproj-project-mode
Draft

Add .csproj "project mode" to winapp run#612
nmetulev wants to merge 12 commits into
mainfrom
nmetulev-run-csproj-project-mode

Conversation

@nmetulev

@nmetulev nmetulev commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

Implements .csproj "project mode" for winapp run per the committed spec specs/winapp-run-csproj.md (v0.4).

winapp run <MyApp.csproj> — or winapp run . / a folder containing a single executable .csproj — now builds the WinUI project and launches it in one step, supporting both packaged and unpackaged WinUI apps. Existing folder mode is unchanged (all new options are optional; project mode is a new branch keyed on the input pointing at / containing a top-level buildable .csproj).

Targets main.

What's implemented (per spec §12 phases)

  1. Input model + routing — positional arg widened DirectoryInfoFileSystemInfo; ResolveInput classifies Folder vs Project; multi-.csproj ambiguity error (prefers the evaluated OutputType over the static XML parse in ProjectDetectionService).
  2. Build integration + property resolutiondotnet build <csproj> -t:Build --getProperty:... (with the required -t:Build); MsBuildPropertyReader handles both the JSON (multi-prop) and raw scalar (single-prop) shapes; repeatable -p/--property forwarded to both build and evaluation; dedicated-flag-beats--p precedence mirrored.
  3. Unpackaged launch + runtime reuse — detection off effective WindowsPackageType (None ⇒ unpackaged); launches the apphost RunCommand exe directly via new AppLauncherService.LaunchExecutable; reuses the existing WinAppSDK runtime install (EnsureWindowsAppRuntimeInstalledAsync), gated on WindowsAppSDKSelfContained.
  4. Packaged launch — loose-layout registration on the absolute TargetDir + AUMID launch (reuses the folder-mode pipeline); guardrail error when a project resolves to packaged but has no Package.appxmanifest.
  5. Arch-correct runtime installWorkspaceSetupService.InstallWindowsAppRuntimeAsync parameterized by the app's resolved --arch (was CLI-process arch only), with a Framework+DDLM presence check (GetInstalledVersion(name, architecture)) to avoid needless reinstalls.
  6. Docs / samples / tests — see below.

Scope guards: .NET-only; no --packaged / --unpackaged flags (packaging is detected from the evaluated WindowsPackageType). A --project selector is provided for solution/multi-project inputs (per spec v0.4). Unpackaged runs reject identity-only options (--manifest, --no-launch, --with-alias, --clean, --unregister-on-exit, --output-appx-directory) — fast-failing before the build when the project is definitively unpackaged, and via an authoritative post-build gate otherwise. --getProperty availability probed via runtime capability (SDK 8.0.100+), erroring clearly otherwise.

New CLI options (project mode only; ignored in folder mode)

-c/--configuration (default Debug), --arch, -r/--runtime, -f/--framework, --project (select the app to launch from a .sln/.slnx or a multi-project directory), --no-build, --no-restore, -p/--property (repeatable).

Test coverage

C# unit/routing (144 pass, Release):

  • MsBuildPropertyReaderTests — JSON/scalar/preamble/empty/case/missing-prop parsing.
  • RunArchHelperTests — arch normalization, RID/Platform mapping.
  • ProjectRunServiceTestsBuildDotnetArguments (default/arm64/--no-build/user--p:Platform suppression/framework), SDK-version parsing, ResolveInput incl. multi-csproj ambiguity.
  • RunCommandProjectModeTests (13) — unpackaged launch + runtime-arch, arm64, self-contained skip, identity-option rejection, forced-unpackaged property forwarding, packaged AUMID + arch, packaged-no-manifest guardrail, SDK-too-old, build-fail exit-code propagation, invalid-arch, resolve ambiguity, folder-mode regression.
  • RunCommandTests — project-mode option parsing + TryResolveArchitecture; existing folder-mode tests unchanged.

Pester sample & guide (spec §10):

  • C2 (must-have) — samples/winui-unpackaged-app: new minimal unpackaged WinUI app; test builds + winapp run . and asserts the app boots off the reused runtime install (verified locally: app process stays alive). Also asserts evaluated WindowsPackageType == None.
  • samples/winui-app (packaged): project-mode winapp run . --no-launch from a clean copy + evaluated WindowsPackageType != None.
  • Both registered in the .github/workflows/test-samples.yml matrix.

Docs / samples updated

docs/usage.md (run section: folder-vs-project auto-detection + project-mode subsection), docs/guides/dotnet.md, docs/fragments/skills/winapp-cli/setup.md (hand-written template; generated SKILL.md / cli-schema.json / .claude regenerated via generate-llm-docs.ps1), new samples/winui-unpackaged-app.

Deferred / notes

  • Q6 (spec's only open item): the NuGet/MSBuild dotnet run hook stays folder-based — unchanged, as decided.
  • npm binaries & full AOT build-cli.ps1 were not run locally: the AOT publish needs the MSVC linker env (missing in this sandbox) and npm bin/ blobs are gitignored/CI-produced. The CLI + tests build clean in Release (0 warnings / 0 errors, warnings-as-errors on), and cli-schema.json / skills were regenerated with the correct 0.4.1 version. CI's Build & Package workflow will produce the AOT artifacts.

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Build Metrics Report

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 32.43 MB 32.71 MB 📈 +286.5 KB (+0.86%)
CLI (x64) 32.73 MB 33.00 MB 📈 +269.5 KB (+0.80%)
MSIX (ARM64) 13.58 MB 13.69 MB 📈 +115.2 KB (+0.83%)
MSIX (x64) 14.43 MB 14.55 MB 📈 +115.9 KB (+0.78%)
NPM Package 28.34 MB 28.56 MB 📈 +217.6 KB (+0.75%)
NuGet Package 28.36 MB 28.58 MB 📈 +222.1 KB (+0.76%)

Test Results

3803 passed, 5 skipped out of 3808 tests in 580.4s (+222 tests, -41.4s vs. baseline)

Test Coverage

94.4% line coverage, 88.4% branch coverage · ⚠️ -0.8% vs. baseline

CLI Startup Time

49ms median (x64, winapp --version) · ✅ +5ms vs. baseline


Updated 2026-07-18 08:34:49 UTC · commit f4e91ed · workflow run

nmetulev added a commit that referenced this pull request Jul 11, 2026
Addresses PR #612 review findings on the highest-risk runtime + launch paths.

H1 (arch-correctness): the reused Windows App Runtime install is now truly
arch-correct with a real presence gate. WorkspaceSetupService.InstallWindows-
AppRuntimeAsync separates the loose-layout/inventory arch (resolved target arch,
used for the win10-<arch> path and ParseMsixInventoryAsync) from the nullable
skip-filter arch, and a new IsWindowsAppRuntimeRegistered(arch) checks for BOTH
a Framework package (Microsoft.WindowsAppRuntime.*, excluding .CBS.) AND a DDLM
(Microsoft.WinAppRuntime.DDLM.*), arch-filtered — mirroring WinAppSDK's
IsRuntimeRegisteredForCurrentUser. EnsureWindowsAppRuntimeInstalledAsync now
throws if the target-arch runtime is still absent after install instead of
treating a missing runtime dir as success, so a cross-arch run no longer skips
the install and crashes at bootstrap.

L2 (folder mode unchanged): the process-arch handling is scoped so folder mode
passes a null arch filter — byte-for-byte identical to the pre-feature behavior.

M3 (PID-reuse / exit-code race): LaunchExecutable now returns an owned
ILaunchedProcess wrapper (new ILaunchedProcess.cs) instead of a bare pid, so the
unpackaged wait/detach/debug flow holds the real Process handle and reads its
exit code directly rather than re-attaching via Process.GetProcessById (which
could hit a reused pid or an already-exited process wrongly reporting 0).

Adds WorkspaceSetupServiceRuntimeGateTests and updates the fakes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
nmetulev added a commit that referenced this pull request Jul 11, 2026
…2, M4, M5)

Addresses PR #612 review findings on project-mode property resolution.

H2 (--json unparseable): stdout in --json mode is now pure JSON. The human-
readable "Building..." banner is gated behind !Json and dotnet build diagnostics
on a failed build are routed to stderr, so a --json consumer's stdout parses.
Adds banner-suppression tests (json vs non-json).

M1 (arg escaping): BuildDotnetArguments uses WindowsCommandLine.JoinArguments
instead of a hand-rolled QuoteIfNeeded that mishandled trailing backslashes.

M2 (--no-build precedence): user -p properties are emitted before the dedicated
-c/--arch/-f flags on the --no-build path too, so the dedicated flag wins
last (matching the build path and WarnOnOverriddenFlags). Adds a precedence test.

M4 (getProperty parse robustness): MsBuildPropertyReader scans each '{' and uses
Utf8JsonReader/TryParseValue, tolerating leading diagnostics/preamble and
trailing content, and only accepts a Properties object — so a single-property
scalar that merely contains '{' is no longer misread as JSON. Adds parser tests.

M5 (multi-project disambiguation): adds coverage for a test project (IsTest-
Project=true) being excluded from the executable set and for the
no-executable-among-multiple ambiguity error. The evaluated OutputType remains
the source of truth downstream (BuildAndResolveAsync rejects non-runnable
OutputType), with the static parse only used to disambiguate at input time.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
nmetulev added a commit that referenced this pull request Jul 11, 2026
Addresses PR #612 review findings.

M8: regenerates src/winapp-npm/src/winapp-commands.ts from the current CLI
schema so it includes the run project-mode options (--arch, --no-build,
--no-restore, -r/--runtime, -c/--configuration, -f/--framework, -p). The
generate-commands --check gate now passes.

H3: samples/winui-app/test.Tests.ps1 registered a loose-layout package then
deleted its backing files without unregistering, polluting the machine/CI. The
AfterAll now reads the identity Name from Package.appxmanifest and removes the
package (Get-AppxPackage | Remove-AppxPackage) before deleting temp/bin/obj.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Outdated
nmetulev added a commit that referenced this pull request Jul 12, 2026
specs/winapp-run-csproj.md's header linked an internal/personal planning repo
(`nikolame/win-devex`) that isn't accessible to public readers of
microsoft/winappCli and whose "overall plan" does not live in this repo. Ahead
of #612 going public, drop that Related line (the same public-appropriateness
rule #616 passed clean). Verified single occurrence: `git grep win-devex` and
`git grep nikolame/` now return nothing on tracked files.

Docs-only; no code, schema, generated-skill, or npm change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b05ed756-966d-4260-a593-f507c4cb2446
Adds a "project mode" to `winapp run` so it can target a .NET
`.csproj` (or a directory containing one) directly, in addition to the
existing build-output folder mode. In project mode winapp restores,
builds, evaluates the project's MSBuild output properties, provisions the
Windows App Runtime for the resolved architecture, and launches the app.

New `run` options: --arch, --configuration, --framework, --no-build,
--no-restore, --property, --runtime. Folder mode is unchanged.

Rebased onto main: reconciled the feature's enriched service contracts
(IWorkspaceSetupService.InstallWindowsAppRuntimeAsync architecture arg +
runtime-package result, IsWindowsAppRuntimeRegistered;
IPackageRegistrationService.GetInstalledVersion architecture arg,
IsPackageInstalled) with main-authored fakes and tests, and regenerated
derived artifacts (docs/cli-schema.json, winapp-cli skills, .claude
mirror, winapp-commands.ts).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
@nmetulev
nmetulev force-pushed the nmetulev-run-csproj-project-mode branch from af418e1 to 65100e7 Compare July 17, 2026 21:07
@nmetulev
nmetulev changed the base branch from winui-devex to main July 17, 2026 21:07
Empty commit to fire a pull_request synchronize event now that the PR
base is main (the rebase force-push happened while the base was still
winui-devex, so no workflows matched their branches: [main] filter).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Commands/RunCommand.ProjectMode.cs
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Project mode now accepts a solution (.sln/.slnx) or a directory containing
one, in addition to a .csproj. When given a solution, `winapp run` resolves
the runnable app project from `dotnet sln list`, classifying each candidate by
evaluated OutputType/IsTestProject, then builds that project with the
solution's $(SolutionDir) and sibling Solution* MSBuild properties defined.
This makes projects that depend on $(SolutionDir) build exactly as they do
under `dotnet build <sln>` / Visual Studio, closing the AI-Dev-Gallery-on-x64
class of failure where a bare .csproj build leaves $(SolutionDir) undefined.

A directory containing a solution prefers the solution over loose .csproj
files. When a solution or directory has multiple runnable app projects,
`run` no longer guesses a startup project: the new `--project <name-or-path>`
selector chooses one, otherwise it errors listing the candidates.

- ProjectRunService: solution/directory resolution + Solution* property
  injection into the build and evaluate passes; `dotnet sln list` parsing.
- RunCommand: new --project option; broadened input description.
- Regenerated cli-schema.json, skills, and npm winapp-commands.ts.
- Tests for solution resolution, ambiguity, --project selection, and
  Solution* property emission.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
nmetulev and others added 2 commits July 17, 2026 15:52
Addresses CodeQL 'Path.Combine may silently drop earlier arguments' on two
non-rooted segment concatenations (win10-<arch> layout dir; per-test temp
dir). Path.Join concatenates without the rooted-reset behavior; result is
identical for these never-rooted segments but no longer matches the flagged
pattern.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Fixes from the PR #612 review (H1, M3, M6, M7, M8, M10, L1, L4, NOTE):

- M3: kill the dotnet/MSBuild process tree on Ctrl+C in
  RunDotnetStreamingAsync so builds are not orphaned.
- M8: gate the build banner + streamed passthrough on log level so
  --quiet keeps stdout clean (route build output to stderr), matching
  --json behavior.
- M6/M7/L4: solution-prop tokens in classification eval, resolve
  --project selectors against the input dir, run SDK check before
  `dotnet sln list`.
- NOTE: skip Windows App Runtime preparation when the resolved project
  has no Microsoft.WindowsAppSDK reference (plain console/desktop Exe),
  avoiding the noisy "could not determine runtime" warning.
- M10: npm run() emits app args after `--` separator (generator fix).
- H1/L1: refresh hand-maintained agent docs + run help text for
  csproj/sln inputs, unpackaged behavior, and app-args-after-`--`.

Tests: add MatchProjectSelector (--project resolution) and
ReferencesWindowsAppSdk (runtime-skip gate) coverage; add a --quiet
banner-suppression test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
L2 (RunArchHelper): move architecture-detection logic fully into
RunArchHelper.DefaultArchitecture(); WorkspaceSetupService.GetSystemArchitecture()
is now a thin delegator instead of the source of truth.

M9 (extract Windows App Runtime install): introduce IWindowsAppRuntimeService /
WindowsAppRuntimeService and move all runtime install / gate / locate / inventory
members out of the oversized WorkspaceSetupService. Rewire production callers
(WorkspaceSetupService, MsixService + partials, UpdateCommand) and DI. This removes
the runtime-related growth this PR introduced; residual WorkspaceSetupService size
is the pre-existing SetupWorkspaceAsync orchestration (out of scope).

M5 (reuse ProjectDetectionService): move the evaluated executable/non-test project
classification into ProjectDetectionService (IsExecutableNonTestProjectAsync) with a
shared IsExecutableOutputType helper used by both the static and evaluated paths.
ProjectRunService now depends on IProjectDetectionService and no longer carries a
parallel classifier.

Pure refactor: no CLI surface/description changes; npm commands and .claude mirror
verified drift-free. Targeted suites pass (detection/project-run 122, runtime/
workspace/msix/update/arch 368).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Fixed
Comment thread src/winapp-CLI/WinApp.Cli/Services/WindowsAppRuntimeService.cs
C#/WinRT authoring projects (Microsoft.Windows.CsWinRT consumers, WinUI
control libraries that author winmds) fail to build via `winapp run`
project mode on hosts with no registered Windows SDK: CsWinRT.targets
defaults CsWinRTWindowsMetadata to a bare SDK version that cswinrt.exe
resolves through a registry KitsRoot10 lookup, which fails and cascades
into WMC XAML errors.

Add a temporary CsWinRTMetadataShimService that, only when no Windows SDK
is registered, resolves the Microsoft.Windows.SDK.NET.Ref ref-pack winmd
folder from the NuGet cache (preferring the TargetPlatformVersion match,
else highest, verifying FoundationContract.winmd) and injects it as
-p:CsWinRTWindowsMetadata into both the build and evaluate passes. It is
skipped when an SDK is installed or the user set the property, and no-ops
cleanly (debug log) when the ref pack is unavailable so the normal error
still surfaces. Marked as a shim pending the upstream cswinrt targets fix.

Adds unit tests for SDK-absent detection and winmd-folder resolution, and
threads the property through ProjectRunService's build/evaluate builders.
Updates specs/winapp-run-csproj.md (new 8.6) and docs/guides/dotnet.md.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs
Comment thread src/winapp-CLI/WinApp.Cli.Tests/ProjectRunServiceTests.cs
Project-mode `winapp run` rejected identity-only options (--no-launch,
--with-alias, --unregister-on-exit, --clean, --manifest,
--output-appx-directory) only in the authoritative post-build gate, so a user
paid the full build cost before the incompatible argument combination was
rejected.

Add a cheap, evaluate-only WindowsPackageType probe
(IProjectRunService.IsDefinitivelyUnpackagedAsync) and a pre-build fast-fail in
RunProjectModeAsync: when an incompatible option is present and the project is
DEFINITIVELY unpackaged (explicit WindowsPackageType=None), reject before
building. Packaged/indeterminate projects (empty WindowsPackageType, or a failed
evaluation) fall through to the build + the authoritative gate, which still
catches the indeterminate-then-unpackaged case that only resolves post-build
(e.g. identity via an emitted recipe). Skipped under --no-build (no build cost
to save).

Extract the incompatible-option collection + message into shared helpers so the
fast-fail and the post-build gate stay in lockstep.

Tests: pre-build fast-fail on definitively-unpackaged; probe skipped for
compatible options and under --no-build; indeterminate builds then rejects at
the gate; service-level probe (None -> true, MSIX/empty -> false, failed
evaluate -> false). Spec §7.3 updated.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds .csproj/solution project mode to winapp run, supporting build-and-launch workflows for packaged and unpackaged WinUI applications.

Changes:

  • Adds project detection, MSBuild evaluation, architecture handling, and direct executable launch.
  • Extracts architecture-aware Windows App Runtime installation.
  • Adds SDK wrappers, documentation, samples, CI coverage, and extensive tests.

Reviewed changes

Copilot reviewed 74 out of 74 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/winapp-npm/src/winapp-commands.ts Updates generated run SDK API.
src/winapp-npm/scripts/generate-commands.mjs Generates repeatable options and run passthrough.
src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.cs Delegates runtime installation.
src/winapp-CLI/WinApp.Cli/Services/ProjectDetectionService.cs Adds evaluated project classification.
src/winapp-CLI/WinApp.Cli/Services/PackageRegistrationService.cs Adds architecture-aware package lookup.
src/winapp-CLI/WinApp.Cli/Services/MsixService.Runtime.cs Uses extracted runtime service.
src/winapp-CLI/WinApp.Cli/Services/MsixService.Identity.cs Adds project-aware runtime preparation.
src/winapp-CLI/WinApp.Cli/Services/MsixService.cs Injects runtime service.
src/winapp-CLI/WinApp.Cli/Services/IWorkspaceSetupService.cs Removes runtime responsibilities.
src/winapp-CLI/WinApp.Cli/Services/IWindowsAppRuntimeService.cs Defines runtime installation contract.
src/winapp-CLI/WinApp.Cli/Services/IProjectRunService.cs Defines project-mode workflow.
src/winapp-CLI/WinApp.Cli/Services/IProjectDetectionService.cs Exposes evaluated classification.
src/winapp-CLI/WinApp.Cli/Services/IPackageRegistrationService.cs Adds architecture filters.
src/winapp-CLI/WinApp.Cli/Services/IMsixService.cs Exposes runtime preparation inputs.
src/winapp-CLI/WinApp.Cli/Services/ILaunchedProcess.cs Abstracts owned child processes.
src/winapp-CLI/WinApp.Cli/Services/IDotNetService.cs Adds streaming dotnet execution.
src/winapp-CLI/WinApp.Cli/Services/ICsWinRTMetadataShimService.cs Defines SDK-less metadata shim.
src/winapp-CLI/WinApp.Cli/Services/IAppLauncherService.cs Adds direct executable launch.
src/winapp-CLI/WinApp.Cli/Services/DotNetService.cs Implements streamed builds.
src/winapp-CLI/WinApp.Cli/Services/CsWinRTMetadataShimService.cs Resolves NuGet WinMD metadata.
src/winapp-CLI/WinApp.Cli/Services/AppLauncherService.cs Launches unpackaged executables.
src/winapp-CLI/WinApp.Cli/Models/ProjectRunModels.cs Adds project-mode models.
src/winapp-CLI/WinApp.Cli/Helpers/RunArchHelper.cs Maps architectures and RIDs.
src/winapp-CLI/WinApp.Cli/Helpers/MsBuildPropertyReader.cs Parses MSBuild property output.
src/winapp-CLI/WinApp.Cli/Helpers/HostBuilderExtensions.cs Registers new services.
src/winapp-CLI/WinApp.Cli/Commands/UpdateCommand.cs Uses runtime service.
src/winapp-CLI/WinApp.Cli/Commands/RunCommand.ProjectMode.cs Implements project-mode routing and launch.
src/winapp-CLI/WinApp.Cli/Commands/RunCommand.cs Adds project inputs and options.
src/winapp-CLI/WinApp.Cli.Tests/WorkspaceSetupServiceRuntimeGateTests.cs Tests runtime presence gating.
src/winapp-CLI/WinApp.Cli.Tests/WorkspaceSetupServiceMsixTests.cs Updates runtime MSIX tests.
src/winapp-CLI/WinApp.Cli.Tests/WorkspaceSetupServiceInventoryTests.cs Tests target-architecture inventory selection.
src/winapp-CLI/WinApp.Cli.Tests/UpdateCommandTests.cs Updates runtime service fakes.
src/winapp-CLI/WinApp.Cli.Tests/RunArchHelperTests.cs Tests architecture mappings.
src/winapp-CLI/WinApp.Cli.Tests/ProjectDetectionServiceTests.cs Supplies dotnet dependency.
src/winapp-CLI/WinApp.Cli.Tests/ProjectDetectionServiceAccessDeniedTests.cs Updates service construction.
src/winapp-CLI/WinApp.Cli.Tests/PackageRegistrationServiceTests.cs Tests architecture mapping.
src/winapp-CLI/WinApp.Cli.Tests/MsixServiceIdentityTests.cs Tests runtime identity preparation.
src/winapp-CLI/WinApp.Cli.Tests/MsBuildPropertyReaderTests.cs Tests MSBuild output parsing.
src/winapp-CLI/WinApp.Cli.Tests/LevelLogger.cs Adds configurable test logger.
src/winapp-CLI/WinApp.Cli.Tests/FakeWorkspaceSetupService.cs Removes runtime behavior.
src/winapp-CLI/WinApp.Cli.Tests/FakeWindowsAppRuntimeService.cs Adds runtime service fake.
src/winapp-CLI/WinApp.Cli.Tests/FakeProjectRunService.cs Adds project-run fake.
src/winapp-CLI/WinApp.Cli.Tests/FakePackageRegistrationService.cs Supports architecture-aware tests.
src/winapp-CLI/WinApp.Cli.Tests/FakeMsixService.cs Records runtime preparation calls.
src/winapp-CLI/WinApp.Cli.Tests/FakeDotNetService.cs Simulates streamed builds and evaluation.
src/winapp-CLI/WinApp.Cli.Tests/FakeCsWinRTMetadataShimService.cs Adds metadata shim fake.
src/winapp-CLI/WinApp.Cli.Tests/FakeAppLauncherService.cs Simulates direct process launch.
src/winapp-CLI/WinApp.Cli.Tests/CsWinRTMetadataShimServiceTests.cs Tests SDK-less metadata resolution.
samples/winui-unpackaged-app/winui-unpackaged-app.csproj Defines unpackaged WinUI sample.
samples/winui-unpackaged-app/test.Tests.ps1 Tests unpackaged project mode.
samples/winui-unpackaged-app/README.md Documents the sample.
samples/winui-unpackaged-app/MainWindow.xaml.cs Implements sample interaction.
samples/winui-unpackaged-app/MainWindow.xaml Defines sample window.
samples/winui-unpackaged-app/App.xaml.cs Starts the sample window.
samples/winui-unpackaged-app/App.xaml Defines sample resources.
samples/winui-unpackaged-app/app.manifest Configures unpackaged process behavior.
samples/winui-unpackaged-app/.gitignore Ignores build artifacts.
samples/winui-app/test.Tests.ps1 Tests packaged project mode.
README.md Lists WinUI samples.
docs/usage.md Documents project-mode CLI usage.
docs/guides/dotnet.md Adds .NET project-mode guidance.
docs/fragments/skills/winapp-cli/setup.md Updates generated skill source.
docs/cli-schema.json Regenerates run command schema.
.github/workflows/test-samples.yml Adds WinUI sample jobs.
.github/plugin/skills/winapp-cli/setup/SKILL.md Regenerates plugin guidance.
.github/plugin/agents/winapp.agent.md Updates agent command guidance.
.claude/skills/winapp-setup/SKILL.md Synchronizes Claude skill.
.claude/agents/winapp.md Synchronizes Claude agent.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/winapp-CLI/WinApp.Cli/Services/CsWinRTMetadataShimService.cs
Comment thread src/winapp-CLI/WinApp.Cli/Services/MsixService.Identity.cs Outdated
Comment thread src/winapp-CLI/WinApp.Cli/Services/MsixService.Identity.cs
Comment thread src/winapp-CLI/WinApp.Cli/Services/IWindowsAppRuntimeService.cs
Comment thread src/winapp-CLI/WinApp.Cli/Commands/RunCommand.cs
Comment thread src/winapp-npm/scripts/generate-commands.mjs
nmetulev and others added 3 commits July 17, 2026 22:22
C1 (CsWinRT shim restore ordering): on a genuinely clean SDK-less host the
Microsoft.Windows.SDK.NET.Ref ref pack may not be on disk when the shim first
resolves, so the very first `dotnet build` fails even though it restores the ref
pack. Add IsWindowsSdkAbsent() to the shim and run an explicit `dotnet restore`
before re-resolving, then build with --no-restore to avoid a double restore.
Only fires when the SDK is absent, the user didn't set the property, and restore
isn't disabled. Adds 4 tests + a BuildRestorePassArguments unit test.

C2 (TFM-aware runtime resolution): a multi-targeted project could gate the
Windows App Runtime on a sibling TFM's Windows App SDK version. Thread the
effective --framework through EnsureWindowsAppRuntimeInstalledAsync and narrow
the package list to the built TFM (FilterPackageListToFramework) before
resolving the SDK version. Fail-open when the TFM is null or absent. Adds
ProjectRunResolution.Framework and 3 filter tests.

C6 (npm generator back-compat): passthrough run/tool/store wrappers dropped the
bare-string appArgs form. Accept string | string[] and normalize before pushing
after `--`. Regenerated winapp-commands.ts (--check clean).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
CI's build-and-package promotes analyzer warnings to errors. Two
pre-existing violations in ProjectRunServiceTests.cs blocked the build:

- CA1859: NewDetection helper returned the interface
  IProjectDetectionService instead of the concrete ProjectDetectionService.
- CA1861: an inline constant array argument to CollectionAssert.AreEqual;
  replaced with direct count + element assertions.

Verified with `dotnet build winapp.sln -c Release -warnaserror` (0 warnings).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
winapp run's solution and multi-.csproj resolution now auto-selects the real
app when a solution also contains its test project (the AI Dev Gallery /
WinUI Gallery shape), instead of erroring on ambiguity.

A WinUI MSTest project is itself a packaged WinExe app that never sets
IsTestProject, so OutputType alone cannot distinguish it from the real app. A
candidate is now classified as a test project when it sets IsTestProject, has
the TestContainer project capability, or references a known test framework/host
package (Microsoft.NET.Test.Sdk, Microsoft.TestPlatform.TestHost, MSTest.*,
xunit*, nunit*). Resolution: one non-test app -> run it; several apps -> require
--project; zero apps but exactly one runnable test project (tests-only solution)
-> run it with a note; several test-only -> require --project. An explicit
--project/.csproj selector is always honored, even to select a test project.

Classification is centralized in IProjectDetectionService.ClassifyRunnableAsync
(replacing IsExecutableNonTestProjectAsync), which prefers an MSBuild evaluation
(OutputType/IsTestProject + ProjectCapability/PackageReference items) and falls
back to a static XML parse when evaluation is unavailable. Adds
MsBuildPropertyReader.ParseItems for the --getItem envelope.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment thread src/winapp-CLI/WinApp.Cli/Helpers/MsBuildPropertyReader.cs
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectDetectionService.cs Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 74 out of 74 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/winapp-CLI/WinApp.Cli/Services/MsixService.Identity.cs:155

  • The packaged project path drops the selected --framework here. GetPackageListAsync returns every TFM, and runtime resolution takes the first WindowsAppSDK reference, so a multi-targeted packaged project built with framework B can install/register against framework A's runtime. Thread resolution.Framework through ExecuteRunPipelineAsync/AddLooseLayoutIdentityAsync and pass it to ResolveDotNetPackageListAsync, as the unpackaged path already does.

Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs
Comment thread src/winapp-CLI/WinApp.Cli/Services/ProjectRunService.cs Outdated
- MatchProjectSelector: skip the leaf-name fallback for a fully qualified
  selector so `--project C:\wrong\App.csproj` no longer silently matches a
  same-named project elsewhere in the solution. Add unit tests covering the
  relative-leaf match, fully-qualified wrong path (no match), and
  fully-qualified correct path.
- ProjectDetectionService.IsKnownTestPackage: collapse foreach to Any().
- MsBuildPropertyReader.TryReadItemsObject: filter non-array groups with Where().

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19da51c1-361e-4b9b-939e-f9c51d4123c5
Comment on lines +395 to +402
foreach (var versionDir in mainDir.GetDirectories().OrderByDescending(d => d.Name, new VersionStringComparer()))
{
var msixDir = TryGetMsixDirectoryFromPath(versionDir);
if (msixDir != null)
{
return msixDir;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants