Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ Conventions for contributors:

### Fixed

- **The Visual Studio preview failed to start every session.** The extension was built
against a newer `System.Text.Json` than Visual Studio binds extensions to, so it failed
to load at runtime. It now tracks the `Microsoft.VisualStudio.SDK` baseline, with a test
to keep it there. The VSIX's advertised minimum host moves to Visual Studio 17.14 to
match that baseline. (PR #1282)

- **The Visual Studio preview now supports packaged (MSIX) apps.** `dotnet new reactor`
generates a packaged app, and previewing one previously failed. It now works with no
project changes. (PR #1282)

- **Wrong code and guidance in the shipped agent-kit skills (spec 064 §4, issue
#1275).** Three gesture snippets in `reactor-input` used WinUI's nested
`ManipulationDelta` shape rather than Reactor's flat gesture structs, and the
Expand Down
2 changes: 1 addition & 1 deletion docs/_pipeline/templates/index.md.dt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ first; everyone else can follow the order.
### 7. Tooling & process

- **[Dev Tooling](dev-tooling.md)** — `mur` CLI, MCP server, VS Code panel, dotnet watch, in-app dev menu
- **[VS Extension](vs-extension.md)** — Rough experimental embedded preview for Visual Studio 2022 (17.8+) and 2026 (18.x)
- **[VS Extension](vs-extension.md)** — Rough experimental embedded preview for Visual Studio 2022 (17.14+) and 2026 (18.x)
- **[Testing](testing.md)** — Headless renderer, structural assertions, async test patterns
- **[Performance](performance.md)** — ETW, EventDispatch, flame graphs
- **[Packaging](packaging.md)** — MSIX, single-file, ARM64, AOT considerations
Expand Down
11 changes: 10 additions & 1 deletion docs/_pipeline/templates/vs-extension.md.dt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ tier: stub

> ⚠️ **Very rough / experimental.** This is the roughest surface in an already experimental Reactor repository. It is meant for early feedback on the embedded-preview direction, not for reliable day-to-day development yet. Expect install friction, solution-load races, HWND/DPI edge cases, blank-window bugs, and breaking changes while this area is hardened.

The Visual Studio Embedded Preview hosts a live Microsoft.UI.Reactor (Reactor) component inside a Visual Studio tool window — Visual Studio 2022 (17.8+) or Visual Studio 2026 (18.x), with the **Visual Studio extension development** workload. Unlike the VS Code preview, which streams screenshots, the Visual Studio extension embeds the real WinUI surface so mouse, keyboard, focus, popups, and accessibility tree inspection work against the running app.
The Visual Studio Embedded Preview hosts a live Microsoft.UI.Reactor (Reactor) component inside a Visual Studio tool window — Visual Studio 2022 (17.14+) or Visual Studio 2026 (18.x), with the **Visual Studio extension development** workload. Unlike the VS Code preview, which streams screenshots, the Visual Studio extension embeds the real WinUI surface so mouse, keyboard, focus, popups, and accessibility tree inspection work against the running app.

## When to use it

Expand All @@ -35,6 +35,15 @@ The component picker is a ComboBox in the tool window chrome. By default it auto
- **L1 hot reload** — edits inside a `Render` body usually apply in place. The embedded UI refreshes without recreating the placeholder HWND.
- **L2 respawn** — rude edits such as record/type shape changes cause `dotnet watch` to rebuild and restart the child. The extension detects the new port/token pair and re-embeds the new child into the same placeholder, normally within about 10 seconds.

## Packaged (MSIX) projects

Packaged projects work with no project changes: `dotnet new reactor` generates a packaged
app that carries the Windows App SDK run support, and the preview supplies the rest. A
project converted to MSIX by hand needs that run support
(`Microsoft.Windows.SDK.BuildTools.WinApp`) added before the preview can attach.

To preview the app unpackaged instead, set `<WindowsPackageType>None</WindowsPackageType>`.

## Known limitations

- WinAppSDK 1.6 or newer is required by the target Reactor app.
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ first; everyone else can follow the order.
### 7. Tooling & process

- **[Dev Tooling](dev-tooling.md)** — `mur` CLI, MCP server, VS Code panel, dotnet watch, in-app dev menu
- **[VS Extension](vs-extension.md)** — Rough experimental embedded preview for Visual Studio 2022 (17.8+) and 2026 (18.x)
- **[VS Extension](vs-extension.md)** — Rough experimental embedded preview for Visual Studio 2022 (17.14+) and 2026 (18.x)
- **[Testing](testing.md)** — Headless renderer, structural assertions, async test patterns
- **[Performance](performance.md)** — ETW, EventDispatch, flame graphs
- **[Packaging](packaging.md)** — MSIX, single-file, ARM64, AOT considerations
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ first; everyone else can follow the order.
### 7. Tooling & process

- **[Dev Tooling](dev-tooling.md)** — `mur` CLI, MCP server, VS Code panel, dotnet watch, in-app dev menu
- **[VS Extension](vs-extension.md)** — Rough experimental embedded preview for Visual Studio 2022 (17.8+) and 2026 (18.x)
- **[VS Extension](vs-extension.md)** — Rough experimental embedded preview for Visual Studio 2022 (17.14+) and 2026 (18.x)
- **[Testing](testing.md)** — Headless renderer, structural assertions, async test patterns
- **[Performance](performance.md)** — ETW, EventDispatch, flame graphs
- **[Packaging](packaging.md)** — MSIX, single-file, ARM64, AOT considerations
Expand Down
11 changes: 10 additions & 1 deletion docs/guide/vs-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

> ⚠️ **Very rough / experimental.** This is the roughest surface in an already experimental Reactor repository. It is meant for early feedback on the embedded-preview direction, not for reliable day-to-day development yet. Expect install friction, solution-load races, HWND/DPI edge cases, blank-window bugs, and breaking changes while this area is hardened.

The Visual Studio Embedded Preview hosts a live Microsoft.UI.Reactor (Reactor) component inside a Visual Studio tool window — Visual Studio 2022 (17.8+) or Visual Studio 2026 (18.x), with the **Visual Studio extension development** workload. Unlike the VS Code preview, which streams screenshots, the Visual Studio extension embeds the real WinUI surface so mouse, keyboard, focus, popups, and accessibility tree inspection work against the running app.
The Visual Studio Embedded Preview hosts a live Microsoft.UI.Reactor (Reactor) component inside a Visual Studio tool window — Visual Studio 2022 (17.14+) or Visual Studio 2026 (18.x), with the **Visual Studio extension development** workload. Unlike the VS Code preview, which streams screenshots, the Visual Studio extension embeds the real WinUI surface so mouse, keyboard, focus, popups, and accessibility tree inspection work against the running app.

## When to use it

Expand All @@ -26,6 +26,15 @@ The component picker is a ComboBox in the tool window chrome. By default it auto
- **L1 hot reload** — edits inside a `Render` body usually apply in place. The embedded UI refreshes without recreating the placeholder HWND.
- **L2 respawn** — rude edits such as record/type shape changes cause `dotnet watch` to rebuild and restart the child. The extension detects the new port/token pair and re-embeds the new child into the same placeholder, normally within about 10 seconds.

## Packaged (MSIX) projects

Packaged projects work with no project changes: `dotnet new reactor` generates a packaged
app that carries the Windows App SDK run support, and the preview supplies the rest. A
project converted to MSIX by hand needs that run support
(`Microsoft.Windows.SDK.BuildTools.WinApp`) added before the preview can attach.

To preview the app unpackaged instead, set `<WindowsPackageType>None</WindowsPackageType>`.

## Known limitations

- WinAppSDK 1.6 or newer is required by the target Reactor app.
Expand Down
4 changes: 2 additions & 2 deletions docs/specs/056-visual-studio-embedded-preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -640,8 +640,8 @@ The csproj is the legacy SDK style (`Microsoft.NET.Sdk` + `<UseWPF>true</UseWPF>

Key NuGet packages:

- `Microsoft.VisualStudio.SDK` 17.8+
- `Microsoft.VSSDK.BuildTools` 17.8+
- `Microsoft.VisualStudio.SDK` 17.14+
- `Microsoft.VSSDK.BuildTools` 17.14+
- `Newtonsoft.Json` (VS already ships it; pin to the version VS 2022 carries to avoid binding redirect headaches) — *or* `System.Text.Json` via the JSON helpers already in the SDK.

### §6.2 Package + tool window
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ real extension from a clean slate.

- [ ] Create `src/vs-reactor-spike/` (gitignored, **not** part of
`Reactor.slnx`). Hand-roll a minimal VSIX project on .NET
Framework 4.7.2 with `Microsoft.VisualStudio.SDK` 17.8+ and
`Microsoft.VSSDK.BuildTools` 17.8+. Single `ToolWindowPane`
Framework 4.7.2 with `Microsoft.VisualStudio.SDK` 17.14+ and
`Microsoft.VSSDK.BuildTools` 17.14+. Single `ToolWindowPane`
whose content is a `Grid` containing only a `HwndHostPlaceholder`.
- [ ] Hand-roll a minimal Reactor target app under `samples/apps/embed-spike/`
(also gitignored or removed before Phase 1 PR) whose `Program.cs`
Expand Down Expand Up @@ -464,12 +464,12 @@ green)

- [ ] Create `src/vs-reactor/Reactor.VsExtension/` with:
- `Reactor.VsExtension.csproj` (.NET Framework 4.7.2, SDK style,
`<UseWPF>true</UseWPF>`, `Microsoft.VisualStudio.SDK` 17.8+
PackageReference, `Microsoft.VSSDK.BuildTools` 17.8+,
`<UseWPF>true</UseWPF>`, `Microsoft.VisualStudio.SDK` 17.14+
PackageReference, `Microsoft.VSSDK.BuildTools` 17.14+,
`<GeneratePkgDefFile>true</GeneratePkgDefFile>`, VSIX
properties).
- `source.extension.vsixmanifest` declaring the Reactor publisher,
name, version, dependencies (VS 2022 17.8+), and the
name, version, dependencies (VS 2022 17.14+), and the
`extension.vsixmanifest` Product/Asset entries.
- Standard VS SDK template files: `Properties/AssemblyInfo.cs`,
`Resources.resx`, `VSPackage.resx`, `index.html` if needed.
Expand Down
4 changes: 2 additions & 2 deletions src/vs-reactor/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Visual Studio Reactor Preview

Live embedded preview pane for Microsoft.UI.Reactor apps in Visual Studio 2022 (17.8+) and Visual Studio 2026 (18.x).
Live embedded preview pane for Microsoft.UI.Reactor apps in Visual Studio 2022 (17.14+) and Visual Studio 2026 (18.x).

> ⚠️ **Very rough / experimental.** This VSIX is the roughest surface in an already experimental repository. It exists to validate the embedded-preview direction and collect feedback; expect install friction, solution-load races, HWND/DPI quirks, blank-window bugs, and breaking changes while it is hardened.

Expand All @@ -12,7 +12,7 @@ Build the full VSIX, double-click it, install into the target Visual Studio hive
pwsh -File src\vs-reactor\Build-Vsix.ps1
```

This requires Visual Studio 2022 (17.8+) or Visual Studio 2026 (18.x) with the **Visual Studio extension development** workload. Phase 1 may ship unsigned for dev distribution, so Visual Studio may show an unsigned-extension warning. Treat installs as developer smoke builds, not stable product drops.
This requires Visual Studio 2022 (17.14+) or Visual Studio 2026 (18.x) with the **Visual Studio extension development** workload. Phase 1 may ship unsigned for dev distribution, so Visual Studio may show an unsigned-extension warning. Treat installs as developer smoke builds, not stable product drops.

## Debug

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,55 @@ private static ProcessStartInfo CreateStartInfo(StartOptions options)
info.EnvironmentVariables["DOTNET_WATCH_RESTART_ON_RUDE_EDIT"] = "1";
info.EnvironmentVariables["DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER"] = "1";
info.EnvironmentVariables["NoDefaultCurrentDirectoryInExePath"] = "1";
ApplyPackagedRunDefaults(info);
return info;
}

/// <summary>
/// Lets a packaged (MSIX) project complete the devtools handshake.
/// </summary>
/// <remarks>
/// <para>
/// A packaged project launched by <c>dotnet watch run</c> goes through the launcher
/// that <c>Microsoft.Windows.SDK.BuildTools.WinApp</c> installs, which the Reactor
/// templates reference. That launcher activates the app by AUMID, which is brokered
/// and therefore has <em>no stdout at all</em> — and stdout is how the child reports
/// <c>CAPTURE_PORT</c> / <c>CAPTURE_TOKEN</c>. The app would start and render while
/// the preview silently waited out its handshake timeout, with no error anywhere to
/// explain it. Setting this property switches the launcher to an execution alias,
/// which inherits stdout.
/// </para>
/// <para>
/// A project that does not carry that run support has nothing to consume this
/// property and must add the package first — a project converted to MSIX by hand is
/// the case in point. See the VS extension guide.
/// </para>
/// <para>
/// Set unconditionally rather than behind a packaged/unpackaged probe: the WinApp
/// targets only consume it when their run support is active, so it is inert for an
/// unpackaged project (verified — an unpackaged launch is byte-identical with and
/// without it), and probing would cost an MSBuild evaluation on every launch.
/// </para>
/// <para>
/// It is passed through the environment, not <c>-p:</c>, for two reasons.
/// <c>dotnet watch</c> rejects <c>-p</c> alongside <c>--project</c> as ambiguous, and
/// an environment property is the lowest-precedence MSBuild property, so a project
/// that explicitly sets <c>&lt;WinAppRunUseExecutionAlias&gt;false&lt;/...&gt;</c>
/// still wins and keeps control.
/// </para>
/// </remarks>
private static void ApplyPackagedRunDefaults(ProcessStartInfo info)
{
info.EnvironmentVariables[WinAppRunUseExecutionAliasVariable] = "true";
}

internal const string WinAppRunUseExecutionAliasVariable = "WinAppRunUseExecutionAlias";

internal static ProcessStartInfo CreateStartInfoForTest(StartOptions options)
{
return CreateStartInfo(options);
}

private static string BuildArguments(StartOptions options)
{
var args = new List<string>
Expand Down
13 changes: 12 additions & 1 deletion src/vs-reactor/Reactor.VsExtension/Reactor.VsExtension.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,18 @@
<PackageReference Include="Microsoft.VSSDK.BuildTools" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" PrivateAssets="all" />
<PackageReference Include="Microsoft.VisualStudio.SDK.Analyzers" PrivateAssets="all" />
<PackageReference Include="System.Text.Json" />
<!-- Do NOT follow the repo-wide System.Text.Json version here.
Visual Studio ships System.Text.Json as a *shared assembly* and binds every
extension to its own copy via a devenv.exe.config <bindingRedirect> with a hard
upper bound (VS 18: oldVersion="0.0.0.0-10.0.0.10"). Redirects unify UPWARD only,
so an extension compiled against a higher assembly version falls outside the
range, no redirect applies, and — because the VSIX does not ship
System.Text.Json.dll (VS strips assemblies it provides) and the package registers
no BindingPath — the CLR finds nothing and throws FileNotFoundException on the
first call that touches the assembly. The safe ceiling is the version
Microsoft.VisualStudio.SDK itself depends on, because every VS that satisfies the
SDK redirects at least that high. VsSharedAssemblyBindingTests gates this. -->
<PackageReference Include="System.Text.Json" VersionOverride="9.0.0" />
Comment thread
azchohfi marked this conversation as resolved.
<!-- Pin transitive MessagePack (via Microsoft.VisualStudio.SDK → StreamJsonRpc) to a
version that includes the GHSA-hv8m-jj95-wg3x LZ4 decompression fix and the
v2.5.205 unsafe-gadget disallow-list additions from upstream PR #2269 that
Expand Down
26 changes: 13 additions & 13 deletions src/vs-reactor/Reactor.VsExtension/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,45 @@
<MoreInfo>https://github.com/microsoft/microsoft-ui-reactor</MoreInfo>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.14,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.14,19.0)">
<ProductArchitecture>arm64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[17.14,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[17.14,19.0)">
<ProductArchitecture>arm64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.14,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.14,19.0)">
<ProductArchitecture>arm64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Product.Community" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Product.Community" Version="[17.14,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Product.Community" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Product.Community" Version="[17.14,19.0)">
<ProductArchitecture>arm64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Product.Pro" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Product.Pro" Version="[17.14,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Product.Pro" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Product.Pro" Version="[17.14,19.0)">
<ProductArchitecture>arm64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Product.Enterprise" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Product.Enterprise" Version="[17.14,19.0)">
<ProductArchitecture>amd64</ProductArchitecture>
</InstallationTarget>
<InstallationTarget Id="Microsoft.VisualStudio.Product.Enterprise" Version="[17.8,19.0)">
<InstallationTarget Id="Microsoft.VisualStudio.Product.Enterprise" Version="[17.14,19.0)">
<ProductArchitecture>arm64</ProductArchitecture>
</InstallationTarget>
</Installation>
<Prerequisites>
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.8,19.0)" DisplayName="Visual Studio core editor" />
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.14,19.0)" DisplayName="Visual Studio core editor" />
</Prerequisites>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" Version="[4.7.2,)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
</PropertyGroup>

<ItemGroup Condition="'$(TF_BUILD)' != 'true'">
<PackageReference Include="System.Text.Json" />
<!-- Must track Reactor.VsExtension.csproj's VersionOverride so the tests bind the same
System.Text.Json identity the shipped extension does. See the comment there. -->
<PackageReference Include="System.Text.Json" VersionOverride="9.0.0" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
</ItemGroup>
Expand Down
Loading
Loading