Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
efd9d29
build(uno): upgrade the Uno SDK to 6.7.22
YoungSx Sep 4, 2026
a9c8a23
chore(styles): re-anchor the NumberBox override to Uno 6.7.103
YoungSx Sep 4, 2026
2e3255a
fix(nav): keep the left-nav selection on the session just created
YoungSx Sep 4, 2026
608210b
test(gates): report why the WASM app never reached first paint
YoungSx Sep 4, 2026
24fd689
test(gates): report the semantic DOM shape when no aria-label matches
YoungSx Sep 4, 2026
d28707f
fix(wasm): render the browser head with Skia to restore accessible names
YoungSx Sep 4, 2026
2de773e
test(gates): ask Skia's WASM head for its accessibility tree before l…
YoungSx Sep 4, 2026
1c51aa6
test(gates): probe the plain id for an AutomationId and report which …
YoungSx Sep 4, 2026
33fcb47
test(gates): locate WASM affordances the way Uno documents it
YoungSx Sep 4, 2026
98e2559
test(gates): assert settings navigation as behaviour, not as clicks
YoungSx Sep 4, 2026
f7a3773
test(wasm): drive smokes through the semantic DOM instead of geometry
YoungSx Sep 4, 2026
86976d1
test(wasm): confirm section arrival on page copy, not on selection state
YoungSx Sep 4, 2026
2b91caf
test(wasm): find start suggestions through the semantic DOM
YoungSx Sep 4, 2026
b37a5ae
test(gates): key fallback scanners on the id attribute, not on the name
YoungSx Sep 4, 2026
5ea0bad
test(gates): match hero suggestion cards by announced name, not by id
YoungSx Sep 4, 2026
74ad21d
test(gates): pin semantic label matches by role to outrun the aria race
YoungSx Sep 4, 2026
b7f5656
test(gates): click the hero card with a trusted pointer, not a synthe…
YoungSx Sep 4, 2026
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
2 changes: 1 addition & 1 deletion BUILD_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dotnet --version
dotnet --info
```

仓库通过 `global.json` 锁定 .NET SDK `10.0.302`,允许同一 feature band 内的 patch 前滚;Uno SDK 锁定为 `6.6.29`。版本不匹配时先安装 .NET 10 SDK,不要手改项目 TFM 或 `global.json`。
仓库通过 `global.json` 锁定 .NET SDK `10.0.302`,允许同一 feature band 内的 patch 前滚;Uno SDK 锁定为 `6.7.22`。版本不匹配时先安装 .NET 10 SDK,不要手改项目 TFM 或 `global.json`。

### 必需与可选依赖

Expand Down
2 changes: 1 addition & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ With Salmon Egg, you can connect to local or remote ACP services, create and res

## Tech Stack

- Uno Platform 6.6+ (repo pin: `Uno.Sdk` 6.6.29)
- Uno Platform 6.7+ (repo pin: `Uno.Sdk` 6.7.22)
- .NET 10 (repo pin: SDK 10.0.302, with 10.0.3xx patch roll-forward)
- WinUI 3 on Windows
- Clean Architecture + MVVM
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Salmon Egg 是一款依托 ACP 协议打造的桌面端智能体客户端。

## 技术栈

- Uno Platform 6.6+(仓库锁定 `Uno.Sdk` 6.6.29
- Uno Platform 6.7+(仓库锁定 `Uno.Sdk` 6.7.22
- .NET 10(仓库锁定 SDK 10.0.302,允许 10.0.3xx patch 前滚)
- WinUI 3(Windows)
- Clean Architecture + MVVM
Expand Down
6 changes: 3 additions & 3 deletions SalmonEgg/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PackageVersion Include="Microsoft.Graph" Version="6.2.0" />
<PackageVersion Include="Microsoft.Identity.Client" Version="4.86.1" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.86.1" />
<!-- Stay on Windows App SDK 1.8 line until Uno 6.6 + WinUI packaging are validated on 2.x. -->
<!-- Stay on Windows App SDK 1.8 line until Uno 6.7 + WinUI packaging are validated on 2.x. -->
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.260710003" />
<PackageVersion Include="Microsoft.WindowsAppSDK.WinUI" Version="1.8.260709004" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="10.0.0" />
Expand All @@ -33,14 +33,14 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.17.0" />
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="10.0.10" />
<PackageVersion Include="System.Security.Permissions" Version="10.0.10" />
<PackageVersion Include="Uno.WinUI.Lottie" Version="6.6.166" />
<PackageVersion Include="Uno.WinUI.Lottie" Version="6.7.103" />
<PackageVersion Include="Uno.Extensions.Reactive" Version="7.2.3" />
<PackageVersion Include="Uno.Extensions.Reactive.WinUI" Version="7.2.3" />
<PackageVersion Include="Uno.Extensions.Reactive.Messaging" Version="7.2.3" />
<PackageVersion Include="Uno.CommunityToolkit.WinUI.UI.Controls.Markdown" Version="7.1.206" />
<PackageVersion Include="Uno.Fonts.Fluent" Version="2.8.1" />
<PackageVersion Include="Uno.Fonts.OpenSans" Version="2.8.1" />
<!-- Uno 6.6 Skia X11 requires Tmds.DBus.Protocol >= 0.92.0; pin a current stable version centrally. -->
<!-- Uno 6.7 Skia X11 requires Tmds.DBus.Protocol >= 0.92.0; pin a current stable version centrally. -->
<PackageVersion Include="Tmds.DBus.Protocol"
Version="0.94.2"
Condition="'$(TargetFramework)' == 'net10.0-desktop'" />
Expand Down
2 changes: 2 additions & 0 deletions SalmonEgg/SalmonEgg/Controls/ChatInputArea.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@

<Button x:Name="SendButton"
x:Uid="SendButton"
AutomationProperties.AutomationId="ChatInputArea.Send"
Content="&#xE724;"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Width="44"
Expand All @@ -365,6 +366,7 @@

<Button x:Name="CancelButton"
x:Uid="CancelButton"
AutomationProperties.AutomationId="ChatInputArea.Cancel"
Content="&#xE711;"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Width="44"
Expand Down
8 changes: 6 additions & 2 deletions SalmonEgg/SalmonEgg/Controls/XtermTerminalView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,19 @@ private void DetachSession(ILocalTerminalSession? session)
}
}

private void OnNavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args)
// Qualify the control type: Uno 6.7 brings in the transitive WebView2Aot package, whose
// WebView2.dll declares a top-level "WebView2" namespace. A global-namespace namespace wins
// simple-name lookup over a using-imported type, so the bare name resolves to that namespace
// (CS0118). The handlers below are for the XAML control, so name it in full.
private void OnNavigationCompleted(Microsoft.UI.Xaml.Controls.WebView2 sender, CoreWebView2NavigationCompletedEventArgs args)
{
if (!args.IsSuccess)
{
ShowFallback();
}
}

private void OnWebMessageReceived(WebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
private void OnWebMessageReceived(Microsoft.UI.Xaml.Controls.WebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
{
_ = DispatchWebMessageAsync(args.WebMessageAsJson);
}
Expand Down
1 change: 1 addition & 0 deletions SalmonEgg/SalmonEgg/MainPage.Shutdown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace SalmonEgg;
/// 只在 <c>Cancel &amp;&amp; SupportsClosingCancellation</c> 时才真的中止关闭。
/// (注意:<c>lib/&lt;tfm&gt;/Uno.UI.dll</c> 是 facade,那里该属性硬编码 false,据它会得出
/// "平台不支持取消"的相反结论。)
/// 该反编译结论取自 6.6.166;升级到 6.7.103 后只确认了符号仍在,未重新反编译逐个 host 的取值。
///
/// 为什么必须在这里 teardown、而不能只依赖宿主返回后再做:desktop 头原先只在
/// <c>Platforms/Desktop/Program.cs</c> 里等 <c>host.RunAsync()</c> 返回后才清理,
Expand Down
12 changes: 12 additions & 0 deletions SalmonEgg/SalmonEgg/SalmonEgg.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,18 @@
<UseDefaultPublishRuntimeIdentifier>false</UseDefaultPublishRuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net10.0-browserwasm'">
<!--
Render the browser head with Skia, matching desktop. The legacy WebAssembly DOM backend stopped
projecting AutomationProperties.Name onto aria-label in Uno 6.7: the app still renders, but no
element carries an accessible name, which is a screen-reader regression and not only a broken
smoke locator. Every accessibility fix in that line targets the Skia WASM semantic DOM instead
(unoplatform/uno#23456, #23722, #24383), and Uno 7 removes the DOM backend outright, so this is
the direction of travel regardless.
-->
<UnoFeatures>SkiaRenderer;WebView;</UnoFeatures>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net10.0-desktop'">
<UnoFeatures>SkiaRenderer;WebView;</UnoFeatures>
<PlatformTarget Condition="'$(PlatformTarget)' == ''">AnyCPU</PlatformTarget>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. -->
<!-- MUX Reference controls\dev\NumberBox\NumberBox.xaml, tag winui3/release/1.7.1, commit 5f27a786ac9 -->
<!-- Adapted from Uno Platform 6.6.166, commit 438b300b6171b3f2712f8897f10ea620784843ca, src/Uno.UI.FluentTheme.v2/Resources/Version2/PriorityDefault/NumberBox.xaml. -->
<!-- Adapted from Uno Platform 6.7.103, commit cd452e3ee242c9a2a8dee5e65ad8088b6f5dbf83, src/Uno.UI.FluentTheme.v2/Resources/Version2/PriorityDefault/NumberBox.xaml. -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand All @@ -12,7 +12,7 @@
<!--
Uno issue unoplatform/uno#24021: the WinUI NumberBox template forces the inner text presenter
to Light while focused, but Skia can retain the dark/transparent background. Keep this copy aligned
with Uno 6.6.166 (commit 438b300b6171b3f2712f8897f10ea620784843ca) and remove it once the upstream
with Uno 6.7.103 (commit cd452e3ee242c9a2a8dee5e65ad8088b6f5dbf83) and remove it once the upstream
issue is fixed in our Uno line.
The application-level NumberBox style is included because the framework template resolves its inner
NumberBoxTextBoxStyle inside the framework resource dictionary; overriding only the inner key is ineffective.
Expand Down Expand Up @@ -379,7 +379,7 @@
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" FontWeight="Normal" Foreground="{ThemeResource TextControlHeaderForeground}" Margin="{ThemeResource TextBoxTopHeaderMargin}" TextWrapping="Wrap" VerticalAlignment="Top" Visibility="Collapsed" x:DeferLoadStrategy="Lazy" />
<Border x:Name="BorderElement" Grid.Row="1" Grid.Column="0" Grid.RowSpan="1" Grid.ColumnSpan="3" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" Control.IsTemplateFocusTarget="True" MinWidth="{TemplateBinding MinWidth}" MinHeight="{TemplateBinding MinHeight}" />
<ScrollViewer x:Name="ContentElement" Grid.Row="1" Grid.Column="0" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" skia:ScrollViewer.IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" skia:ScrollViewer.IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Foreground="{TemplateBinding Foreground}" IsTabStop="False" AutomationProperties.AccessibilityView="Raw" ZoomMode="Disabled" />
<TextBlock x:Name="PlaceholderTextContentPresenter" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Foreground="{Binding PlaceholderForeground, RelativeSource={RelativeSource TemplatedParent}, TargetNullValue={ThemeResource TextControlPlaceholderForeground}}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Text="{TemplateBinding PlaceholderText}" TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" IsHitTestVisible="False" />
<TextBlock x:Name="PlaceholderTextContentPresenter" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Foreground="{Binding PlaceholderForeground, RelativeSource={RelativeSource TemplatedParent}, TargetNullValue={ThemeResource TextControlPlaceholderForeground}}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Text="{TemplateBinding PlaceholderText}" TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" IsHitTestVisible="False" AutomationProperties.AccessibilityView="Raw" />
<Button x:Name="DeleteButton" Grid.Row="1" Grid.Column="1" Style="{StaticResource DeleteButtonStyle}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" Padding="{ThemeResource HelperButtonThemePadding}" IsTabStop="False" Visibility="Collapsed" AutomationProperties.AccessibilityView="Raw" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Right" MinWidth="40" VerticalAlignment="Stretch" />
<ContentPresenter x:Name="DescriptionPresenter" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="{TemplateBinding Description}" Foreground="{ThemeResource SystemControlDescriptionTextForegroundBrush}" AutomationProperties.AccessibilityView="Raw" x:Load="False" />
<TextBlock x:Name="PopupIndicator" Grid.Row="1" Grid.Column="2" Visibility="Collapsed" Margin="{StaticResource NumberBoxPopupIndicatorMargin}" Foreground="{ThemeResource NumberBoxPopupIndicatorForeground}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="12" Text="&#xEC8F;" FontFamily="{ThemeResource SymbolThemeFontFamily}" AutomationProperties.AccessibilityView="Raw" />
Expand Down
2 changes: 1 addition & 1 deletion SalmonEgg/global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
// To update the version of Uno please update the version of the Uno.Sdk here. See https://aka.platform.uno/upgrade-uno-packages for more information.
"msbuild-sdks": {
"Uno.Sdk": "6.6.29"
"Uno.Sdk": "6.7.22"
},
"sdk": {
"allowPrerelease": false
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"msbuild-sdks": {
"Uno.Sdk": "6.6.29"
"Uno.Sdk": "6.7.22"
},
"sdk": {
"version": "10.0.302",
Expand Down
15 changes: 11 additions & 4 deletions scripts/gates/run-wasm-smoke-gates.sh
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,17 @@ echo "[gate] Restore browserwasm dependencies"
"${DOTNET_BIN}" restore "${PROJECT}"

echo "[gate] Clean browserwasm output"
"${DOTNET_BIN}" clean "${PROJECT}" -c "${CONFIGURATION}" -f net10.0-browserwasm -v minimal

echo "[gate] Build browserwasm app"
"${DOTNET_BIN}" build "${PROJECT}" -c "${CONFIGURATION}" -f net10.0-browserwasm --no-restore -v minimal
"${DOTNET_BIN}" clean "${PROJECT}" -c "${CONFIGURATION}" -f net10.0-browserwasm -v minimal \
-p:IsUiAutomationMappingEnabled=true

# IsUiAutomationMappingEnabled is what makes AutomationProperties.AutomationId reach the DOM at all:
# per Uno's AutomationProperties reference it is off by default "to avoid performance overhead", and
# when on, WASM publishes a `xamlautomationid` attribute plus aria-label on the element. The smokes
# locate every affordance by AutomationId, so the gate build has to opt in. Kept to the gate rather
# than the project file precisely because of that documented cost - shipped builds leave it off.
echo "[gate] Build browserwasm app (UI automation mapping enabled for the smokes)"
"${DOTNET_BIN}" build "${PROJECT}" -c "${CONFIGURATION}" -f net10.0-browserwasm --no-restore -v minimal \
-p:IsUiAutomationMappingEnabled=true

# Stage Debug HotReload browser module when build leaves it only under obj/.
HOTRELOAD_MODULE_NAME="Microsoft.DotNet.HotReload.WebAssembly.Browser.lib.module.js"
Expand Down
9 changes: 6 additions & 3 deletions scripts/gates/wasm-focus-boundary-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,17 @@ async function revealGamepadDiagnosticsSection(page) {
// toggle (or the nearest ExpanderToggleButton whose text mentions gamepad).
const togglePoint = await page.evaluate(() => {
const normalize = value => (value ?? "").replace(/\s+/g, " ").trim().toLowerCase();
const start = document.querySelector('[aria-label="Diagnostics.GamepadStart"]');
// Fallback rectangle scanner: match the id contract, not the name. These buttons carry no
// AutomationProperties.Name, so their aria-label only *coincidentally* equals the automation
// id (the nameless fallback); xamlautomationid keeps working whether or not a name is added.
const start = document.querySelector('[xamlautomationid="Diagnostics.GamepadStart"]');
const expander =
start?.closest(".uno-expander")
?? start?.closest("[class*='Expander']")
?? start?.closest("details")
?? null;
const ownedToggle =
expander?.querySelector('[aria-label="ExpanderToggleButton"], button, [role="button"], .uno-expanderheader, summary')
expander?.querySelector('[xamlautomationid="ExpanderToggleButton"], button, [role="button"], .uno-expanderheader, summary')
?? null;
if (ownedToggle) {
const rect = ownedToggle.getBoundingClientRect();
Expand All @@ -109,7 +112,7 @@ async function revealGamepadDiagnosticsSection(page) {
}

const toggles = Array.from(
document.querySelectorAll('[aria-label="ExpanderToggleButton"], button, [role="button"], summary'));
document.querySelectorAll('[xamlautomationid="ExpanderToggleButton"], button, [role="button"], summary'));
for (const toggle of toggles) {
const text = normalize(toggle.textContent);
if (text.includes("gamepad") || text.includes("手柄") || text.includes("compatibility monitor") || text.includes("兼容性监测")) {
Expand Down
Loading
Loading