Winui top level exe#109
Open
Jaylyn-Barbee wants to merge 9 commits into
Open
Conversation
BENCH-2: api/controls verb wrappers always re-mapped underlying CLI exit 1 to ExitCode.ExecutionError (4), losing the usage-vs-execution distinction. Added ErrorClassification heuristic that pattern-matches captured stderr for known usage phrases (empty query, --max validation, 'Multiple projects cached', unknown args) and routes to UsageError (2). Wired into both ApiVerbCommand and ControlsVerbCommand, including the non-JSON path via a new TeeWriter that streams to console while also capturing for classification. BENCH-3: 'api search' --max was ignored when results were ambiguous. QueryEngine returned early through the ambiguous-groups branch without applying Take(maxResults). Capped that iteration. 'api search Button --max 3' goes from ~450 lines to ~25. BENCH-4: temp Directory.Build.props could leak when a post-build MSBuild target (e.g. winapp create-debug-identity) failed and MSBuild still held the file handle when AnalyzerInjection.Dispose ran. Widened BuildCommand try/finally to cover all post-build work; replaced silent IOException swallow in TryDelete with retry-with-backoff (3x at 100ms) and a user-visible warning (non-JSON) if the file still won't go away. BENCH-9: src/tools/winui-cli/README.md verb tables listed fictional api verbs (info, path, lookup-attribute, list-namespaces, list-types, prune) and the wrong controls verb (detail vs get). Replaced with live --help output and added a callout about partial schema coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…g JSON verbs Previously only 6 of 18 --json payloads had a committed schema. The remaining 12 (api: update, members, types, enums, check-property, namespaces, packages, projects, stats; controls: get, list, update) all emitted a 'schema': 'winui.<noun>.<verb>.v1' discriminator at runtime but no matching .schema.json existed and no drift gate enforced their shape — meaning hosts could not rely on the contract the payload claimed. Added a dedicated [WinUiJsonSchema]-tagged record per verb (same text-wrapper shape today, but distinct types so future per-verb shape changes show up in -CheckSchemaDrift). ApiVerbCommand and ControlsVerbCommand dispatch by schema id to the matching WinUiJsonContext source-gen serializer. Result: 18 schemas under plugins/winui/schemas/ — every --json verb is now contract-locked and drift-checked. README claim about full schema coverage is now true. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
H1 (schema discriminator was unconstrained): SchemaGen now emits
'const': '<schemaName>' for the schema string field of every root
[WinUiJsonSchema] record. Previously the 13 text-wrapper verbs all
shipped byte-identical contracts that only differed in title/\, so
a payload claiming to be 'winui.api.search.v1' would also pass
validation as 'winui.api.stats.v1'. Now the discriminator is locked
and the per-verb schema files mean something.
H2 (ErrorClassification was a fragile English substring search):
rewrote to anchor patterns to line-leading prefixes (Trim+StartsWith
per stderr line) and to prefer a '[USAGE]' sentinel when the
underlying CLIs adopt it. Each remaining string-match entry now cites
the upstream source file/line so a reword shows up as an explicit
contract change in code review. Coverage is unchanged for the BENCH-2
cases — verified by spot-test (empty query and --max 0 both exit 2).
H3 (deprecation aliases for commands that never shipped): deleted
BuildRunAliasCommand, SearchAliasCommand, WinMdAliasCommand and their
registrations. This is winui.exe's first release; nothing to
deprecate. Removed the now-unused Output.Deprecation helper too.
M2 (dead retry tail in TryDeleteWithRetry): collapsed the 3-loop + 4th
ad-hoc attempt into one loop with 'when (attempt < 2)' filters, which
makes the intent ('retry twice, then check') visible. Removed the
unused TryDelete helper; Prepare's catch block now uses
TryDeleteWithRetry.
M4 (CHANGELOG): added Unreleased entries under Added/Changed covering
the new sidecar, schema set, drift gate, and analyzer injection.
L3 (silent fallback in verb dispatch): SerializeForVerb in both
ApiVerbCommand and ControlsVerbCommand now throws on an unrecognized
schema id instead of falling back to the search wrapper. Adding a verb
without registering its [WinUiJsonSchema] record will now fail loudly
at runtime instead of silently shipping under the wrong contract.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sult.v1
Previously, every verb whose JSON payload was just 'wrap the inner CLI's text
output with an exit code' had its own [WinUiJsonSchema]-tagged record (10 api +
4 controls = 14 records), each producing a byte-identical .schema.json file that
differed only in the title/$id/const string. That was contract theater: 14
distinct on-disk schemas conveying zero distinct information.
Replace with a single TextResultV1 shape carrying a 'verb' discriminator field
(e.g. verb="api.update" / verb="controls.search"). Consumers dispatch on
the verb field; schema validators check shape via the single committed
winui.text-result.v1 schema. Structured verbs (project.build, analyzer.info)
keep their own [WinUiJsonSchema] records — when a text wrapper graduates to
real typed fields it gets promoted out of TextResultV1 at that point.
Schemas on disk: 18 -> 5 (text-result + project.build + analyzer.info + error
+ help). The build's stale-file cleanup (build-tools.ps1 lines 208-212) deletes
the 14 obsolete files automatically. Drift gate still passes.
Breaking wire-format change for text-wrapper verbs:
before: {"schema":"winui.api.update.v1","exitCode":0,"output":...}
after: {"schema":"winui.text-result.v1","verb":"api.update",
"exitCode":0,"output":...}
Acceptable because the PR is unmerged and no external consumer has pinned
the old schema ids.
Files changed:
- Schemas/JsonPayloads.cs: delete 14 records + add TextResultV1; trim JsonContext
- Commands/Api/ApiVerbCommand.cs: drop 10-case SerializeForVerb switch + SchemaId
- Commands/Controls/ControlsVerbCommand.cs: same for 4-case switch + SchemaId
- SchemaGen/Program.cs: freshen now-stale 'api.search vs api.stats' example
in the const-lock comment
- README.md: document two-tier identity (shape via schema, command via verb)
- CHANGELOG.md: reword Added bullet to describe the new contract
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ommand Post-schema-collapse, ApiVerbCommand and ControlsVerbCommand became byte-for- byte identical except for (1) which inner runner to invoke, (2) which CommandPrefix global to set, (3) the noun string baked into help/error/payload. Two files maintaining the same logic with three substitutions is the same anti-pattern the schema collapse just removed at the wire-format layer. Lift the three substitutions into constructor parameters of a single WrappingVerbCommand class. ApiCommand/ControlsCommand wire up the noun- specific runner + prefix-setter once via a tiny static Verb() helper, then build verbs the same way as before. Adding a third 'wrap an inner CLI as a winui noun' becomes one Register(Verb(...)) call instead of a new file. Files changed: - Commands/WrappingVerbCommand.cs: new (75 lines) - Commands/Api/ApiVerbCommand.cs: deleted - Commands/Controls/ControlsVerbCommand.cs: deleted - Commands/Api/ApiCommand.cs: Register(new ApiVerbCommand(...)) -> Register(Verb(...)) - Commands/Controls/ControlsCommand.cs: same Smoke-tested: - 'winui --json api stats' (no project) -> winui.error.v1 / api_stats_failed - 'winui --json controls list' -> winui.text-result.v1 / verb=controls.list - 'winui --json controls search ''' -> winui.error.v1 / controls_search_failed, exit=2 Drift gate passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the prebuilt winui.exe from plugins/winui/ so it follows the same pattern as winmd-cli: source lives in src/tools/, the build produces the AOT exe under bin/publish/, but no binary is committed to the plugins tree. - git rm plugins/winui/winui.exe (11 MB binary removed from tracking) - build-tools.ps1: remove sidecar payload-refresh section - winui-dev.agent.md: revert to main-branch wording (winui-search only) - README.md, CHANGELOG.md, winui-cli/README.md: update references Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The schemas are winui-cli build artifacts, not part of the installable Copilot plugin. Move them to src/tools/winui-cli/schemas/ to keep plugins/winui/ focused on plugin content (agent, skills, references). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Native-AOT winui.exe sidecar CLI that unifies existing WinUI tooling (winmd-cli, winui-search, analyzer payload, and build/run workflow) behind a single winui <noun> <verb> command surface, with versioned JSON output contracts backed by committed JSON Schemas.
Changes:
- Added
src/tools/winui-cli/(command registry, verb wrappers, project build + transient analyzer injection, analyzer info) plus schema generation tooling and committed schemas. - Refactored
winmd-cliandwinui-searchto expose in-process “runner” entry points and to support sidecar-friendly usage strings. - Updated build/docs to include
winui-cliand schema drift checks (scripts/build-tools.ps1 -CheckSchemaDrift, README/CHANGELOG updates).
Reviewed changes
Copilot reviewed 42 out of 44 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tools/winui-search/WinUiSearchInvocation.cs | Adds a shared command-prefix source for accurate usage strings under sidecar dispatch. |
| src/tools/winui-search/Program.cs | Exposes a reusable runner entry point and improves argument validation / usage messages. |
| src/tools/winui-search/GalleryFetcher.cs | Updates WinUI Gallery scraping to the post-2024 layout and supports SampleDefinition parsing. |
| src/tools/winui-search/DataLoader.cs | Switches resource loading to typeof(DataLoader).Assembly for library embedding scenarios. |
| src/tools/winui-search-lib/winui-search-lib.csproj | New library wrapper to reuse winui-search sources/resources in-process. |
| src/tools/winui-cli/winui-cli.csproj | New sidecar CLI project that references winmd/winui-search libs and embeds analyzer payload. |
| src/tools/winui-cli/schemas/winui.text-result.v1.schema.json | Adds committed schema for the shared “text-result” JSON payload. |
| src/tools/winui-cli/schemas/winui.project.build.v1.schema.json | Adds committed schema for structured project build results. |
| src/tools/winui-cli/schemas/winui.help.v1.schema.json | Adds committed schema for help envelopes. |
| src/tools/winui-cli/schemas/winui.error.v1.schema.json | Adds committed schema for error envelopes. |
| src/tools/winui-cli/schemas/winui.analyzer.info.v1.schema.json | Adds committed schema for analyzer info results. |
| src/tools/winui-cli/schemas/manifest.json | Adds manifest of generated schemas + hashes for drift/provenance checks. |
| src/tools/winui-cli/Schemas/JsonPayloads.cs | Defines JSON payload records + schema discriminator attribute + STJ source-gen context. |
| src/tools/winui-cli/SchemaGen/WinUi.SchemaEmit.csproj | Adds a small schema-emitter console project. |
| src/tools/winui-cli/SchemaGen/Program.cs | Implements schema emission via MetadataLoadContext reflection + manifest generation. |
| src/tools/winui-cli/README.md | Documents the sidecar surface, build flow, and schema generation/drift contract. |
| src/tools/winui-cli/Program.cs | Adds top-level program entry routing to help/version/registry execution. |
| src/tools/winui-cli/Commands/WrappingVerbCommand.cs | Implements a generic “wrap inner CLI” verb to unify api/controls behavior + JSON wrapping. |
| src/tools/winui-cli/Commands/TeeWriter.cs | Adds a tee writer to stream stderr live while capturing it for classification. |
| src/tools/winui-cli/Commands/Project/ProjectCommand.cs | Registers the project noun and its verbs. |
| src/tools/winui-cli/Commands/Project/BuildCommand.cs | Implements winui project build (MSBuild/dotnet build, analyzer injection, optional winapp run). |
| src/tools/winui-cli/Commands/Output.cs | Centralizes error envelope emission (JSON) and human error output. |
| src/tools/winui-cli/Commands/ICommand.cs | Introduces the command interface used across the registry/tree. |
| src/tools/winui-cli/Commands/HelpRenderer.cs | Implements human + JSON help rendering for root/nodes/verbs. |
| src/tools/winui-cli/Commands/GlobalOptions.cs | Adds global option parsing (--json, --no-color, --quiet). |
| src/tools/winui-cli/Commands/ExitCode.cs | Defines standardized exit codes for the sidecar. |
| src/tools/winui-cli/Commands/ErrorClassification.cs | Adds heuristics to map inner CLI failures into standardized exit codes. |
| src/tools/winui-cli/Commands/Controls/ControlsCommand.cs | Adds controls noun wired to winui-search runner with correct usage prefixing. |
| src/tools/winui-cli/Commands/CommandRegistry.cs | Registers the top-level noun tree (api/controls/project/analyzer). |
| src/tools/winui-cli/Commands/CommandNode.cs | Implements a tree node that routes to child commands and renders node help. |
| src/tools/winui-cli/Commands/Api/ApiCommand.cs | Adds api noun wired to winmd runner with correct usage prefixing. |
| src/tools/winui-cli/Commands/Analyzer/InfoCommand.cs | Adds analyzer info verb and JSON/human output. |
| src/tools/winui-cli/Commands/Analyzer/AnalyzerPayload.cs | Encapsulates embedded analyzer payload discovery/extraction metadata. |
| src/tools/winui-cli/Commands/Analyzer/AnalyzerInjection.cs | Implements transient analyzer injection via temp props + cleanup with retry/backoff. |
| src/tools/winui-cli/Commands/Analyzer/AnalyzerCommand.cs | Registers analyzer noun. |
| src/tools/winmd-lib/winmd-lib.csproj | New library wrapper to reuse winmd-cli sources in-process. |
| src/tools/winmd-cli/WinMdInvocation.cs | Adds shared command-prefix source for accurate usage/error strings under sidecar dispatch. |
| src/tools/winmd-cli/QueryEngine.cs | Updates usage messages to use the shared prefix; applies --max to ambiguous results. |
| src/tools/winmd-cli/Program.cs | Exposes a reusable runner entry point and keeps a thin exe entrypoint. |
| scripts/build-tools.ps1 | Adds winui-cli build + schema emission + schema drift check mode. |
| README.md | Documents the new winui sidecar tool and links its README. |
| CHANGELOG.md | Adds release notes for winui-cli, schemas, schema drift checks, and library wrappers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+52
to
+54
| var payload = new HelpEnvelopeV1( | ||
| $"winui.{node.Name}.help.v1", | ||
| $"winui {node.Name}", |
Comment on lines
+86
to
+88
| var payload = new HelpEnvelopeV1( | ||
| $"winui.{noun}.{verb.Name}.help.v1", | ||
| $"winui {noun} {verb.Name}", |
Comment on lines
+54
to
+57
| var msbuild = FindMsBuild(); | ||
| var buildArgs = msbuild != null | ||
| ? new[] { "/nologo", "/v:m" }.Concat(extra).Concat(new[] { project }).ToArray() | ||
| : ToDotnetArgs(project, extra); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR bundles winmd, ui-search, build and run and the Roslyn analyzer into one CLI that can serve as a side car to apps like
winapp.Related Issue
Fixes #105
Type of Change
Affected area
plugins/winui/agents/)plugin.json,plugins/winui/)Checklist
SKILL.mdfrontmatter still valid; cross-references to other skills still resolve.ps1script changed: tested under defaultRemoteSignedexecution policyREADME.mdupdated## [Unreleased]inCHANGELOG.mdScreenshots / Demo
Additional Notes
AI Description
This section is auto-generated by AI when the PR is opened or updated. To opt out, delete this entire section including the marker comments.