diff --git a/src/OpenClaw.Tray.WinUI/Services/SetupExistingGatewayClassifier.cs b/src/OpenClaw.Tray.WinUI/Services/SetupExistingGatewayClassifier.cs index 8f086b51b..289037250 100644 --- a/src/OpenClaw.Tray.WinUI/Services/SetupExistingGatewayClassifier.cs +++ b/src/OpenClaw.Tray.WinUI/Services/SetupExistingGatewayClassifier.cs @@ -106,10 +106,7 @@ private static async Task HasAppOwnedLocalWslGatewayAsync( private static bool HasLocalSetupEvidence(GatewayRegistry? registry, string localDataPath) { if (registry is not null - && registry.GetAll().Any(record => - record.IsLocal - && record.SshTunnel is null - && LocalGatewayUrlClassifier.IsLocalGatewayUrl(record.Url))) + && registry.GetAll().Any(WslKeepAlivePolicy.IsSetupManagedLocalRecord)) { return true; } diff --git a/src/OpenClaw.Tray.WinUI/Services/WslKeepAlivePolicy.cs b/src/OpenClaw.Tray.WinUI/Services/WslKeepAlivePolicy.cs index 5745a0f6b..86643b532 100644 --- a/src/OpenClaw.Tray.WinUI/Services/WslKeepAlivePolicy.cs +++ b/src/OpenClaw.Tray.WinUI/Services/WslKeepAlivePolicy.cs @@ -10,17 +10,12 @@ internal static class WslKeepAlivePolicy public static bool ShouldStart(GatewayRecord? activeRecord, string? legacyGatewayUrl) { - if (activeRecord is not null) - { - if (activeRecord.SshTunnel is not null) - return false; + _ = legacyGatewayUrl; - return activeRecord.IsLocal - || !string.IsNullOrWhiteSpace(activeRecord.SetupManagedDistroName) - || LocalGatewayUrlClassifier.IsLocalGatewayUrl(activeRecord.Url); - } + if (activeRecord is not null) + return IsSetupManagedLocalRecord(activeRecord); - return LocalGatewayUrlClassifier.IsLocalGatewayUrl(legacyGatewayUrl ?? string.Empty); + return false; } public static string? ResolveDistroName( diff --git a/tests/OpenClaw.Tray.Tests/StartupSetupStateTests.cs b/tests/OpenClaw.Tray.Tests/StartupSetupStateTests.cs index 4d8035214..beda9c8c7 100644 --- a/tests/OpenClaw.Tray.Tests/StartupSetupStateTests.cs +++ b/tests/OpenClaw.Tray.Tests/StartupSetupStateTests.cs @@ -274,6 +274,7 @@ public async Task ClassifyAsync_ReturnsAppOwnedLocalWsl_WhenDistroAndLocalRegist Id = "local-gateway", Url = "ws://localhost:18789", IsLocal = true, + SetupManagedDistroName = "OpenClawGateway", SharedGatewayToken = "shared-token" }); var wsl = new FakeWslCommandRunner([new WslDistroInfo("OpenClawGateway", "Stopped", 2)]); @@ -288,6 +289,32 @@ public async Task ClassifyAsync_ReturnsAppOwnedLocalWsl_WhenDistroAndLocalRegist Assert.Equal(SetupExistingGatewayKind.AppOwnedLocalWsl, kind); } + [Fact] + public async Task ClassifyAsync_TreatsNativeLoopbackGatewayAsExternalOnly_EvenWhenOpenClawGatewayDistroExists() + { + using var temp = TempSettings.Create(); + var settings = new SettingsManager(temp.Path); + var registry = new GatewayRegistry(temp.Path); + registry.AddOrUpdate(new GatewayRecord + { + Id = "native-gateway", + Url = "wss://127.0.0.1:18789", + FriendlyName = "Desktop-A Native Gateway", + IsLocal = true, + SharedGatewayToken = "shared-token" + }); + var wsl = new FakeWslCommandRunner([new WslDistroInfo("OpenClawGateway", "Stopped", 2)]); + + var kind = await SetupExistingGatewayClassifier.ClassifyAsync( + registry, + settings, + temp.Path, + wsl, + localDataPath: temp.Path); + + Assert.Equal(SetupExistingGatewayKind.ExternalOnly, kind); + } + [Fact] public async Task ClassifyAsync_StaleOpenClawDistroWithoutLocalEvidence_DoesNotTriggerLocalReplacementWarning() { diff --git a/tests/OpenClaw.Tray.Tests/WslKeepAlivePolicyTests.cs b/tests/OpenClaw.Tray.Tests/WslKeepAlivePolicyTests.cs index 327468ec0..a4e30d00e 100644 --- a/tests/OpenClaw.Tray.Tests/WslKeepAlivePolicyTests.cs +++ b/tests/OpenClaw.Tray.Tests/WslKeepAlivePolicyTests.cs @@ -19,6 +19,20 @@ public void ShouldStart_UsesActiveLocalRegistryRecord_WhenLegacySettingsAreEmpty Assert.True(WslKeepAlivePolicy.ShouldStart(record, legacyGatewayUrl: null)); } + [Fact] + public void ShouldStart_DoesNotStartForManualNativeLocalRecord() + { + var record = new GatewayRecord + { + Id = "native-local", + Url = "wss://127.0.0.1:18789", + FriendlyName = "Desktop-A Native Gateway", + IsLocal = true, + }; + + Assert.False(WslKeepAlivePolicy.ShouldStart(record, legacyGatewayUrl: null)); + } + [Fact] public void ShouldStart_DoesNotFallBackToLegacyLocalUrl_WhenActiveRecordIsRemote() { @@ -47,9 +61,9 @@ public void ShouldStart_DoesNotTreatSshTunnelLocalForwardAsWslGateway() } [Fact] - public void ShouldStart_FallsBackToLegacyLocalUrl_WhenNoActiveRecordExists() + public void ShouldStart_DoesNotFallBackToLegacyLocalUrl_WhenNoActiveRecordExists() { - Assert.True(WslKeepAlivePolicy.ShouldStart(activeRecord: null, "ws://127.0.0.1:18789")); + Assert.False(WslKeepAlivePolicy.ShouldStart(activeRecord: null, "ws://127.0.0.1:18789")); } [Fact]