Skip to content

Winui top level exe#109

Open
Jaylyn-Barbee wants to merge 9 commits into
stagingfrom
jay/winuiexe
Open

Winui top level exe#109
Jaylyn-Barbee wants to merge 9 commits into
stagingfrom
jay/winuiexe

Conversation

@Jaylyn-Barbee

Copy link
Copy Markdown

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

  • ✨ New feature

Affected area

  • Agent (plugins/winui/agents/)
  • Skill:
  • Tool:
  • Plugin metadata (plugin.json, plugins/winui/)
  • Repo-level docs / governance

Checklist

  • Tested locally on Windows (build + agent invocation if applicable)
  • If a skill changed: SKILL.md frontmatter still valid; cross-references to other skills still resolve
  • If a .ps1 script changed: tested under default RemoteSigned execution policy
  • If a CLI command or agent invocation changed: README.md updated
  • New tests added for new functionality (if applicable)
  • If user-facing: added a bullet to ## [Unreleased] in CHANGELOG.md

Screenshots / Demo

image

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.

Jaylyn-Barbee and others added 9 commits June 15, 2026 13:19
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>
@Jaylyn-Barbee Jaylyn-Barbee marked this pull request as ready for review June 16, 2026 14:59
@Jaylyn-Barbee Jaylyn-Barbee requested a review from Copilot June 16, 2026 14:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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-cli and winui-search to expose in-process “runner” entry points and to support sidecar-friendly usage strings.
  • Updated build/docs to include winui-cli and 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);
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