Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/OpenClaw.Connection/NodeConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public async Task ConnectAsync(string gatewayUrl, GatewayCredential credential,
catch (Exception ex)
{
_logger.Warn($"[NodeConnector] ClientCreated handler threw: {ex.Message}");
_diagnostics?.Record("node", "ClientCreated handler failed; node may connect without capabilities", ex.Message);
}

_client.StatusChanged += (s, e) => StatusChanged?.Invoke(this, e);
Expand Down
41 changes: 36 additions & 5 deletions src/OpenClaw.Tray.WinUI/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
SshTunnelCommandLine.CanForwardBrowserProxyPort(_settings.SshTunnelRemotePort, _settings.SshTunnelLocalPort);
if (_settings.NodeBrowserProxyEnabled && !includeBrowserProxyForward)
{
Logger.Warn("SSH tunnel browser proxy forward disabled because the derived port would be invalid");

Check warning on line 103 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 103 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 103 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 103 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 103 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 103 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}

_sshTunnelService.EnsureStarted(
Expand Down Expand Up @@ -132,7 +132,7 @@
var settings = _settings ?? new SettingsManager();
// NodeService is still required for capability registration on the manager's
// WindowsNodeClient (via App.xaml.cs ClientCreated → AttachClient bridge).
var nodeService = EnsureNodeServiceForLocalGatewaySetup(settings);
var nodeService = EnsureNodeService(settings);
// Suppress manager auto-start of node during setup so the engine retains
// strict phase ordering (operator paired → WSL CLI device-approve → node
// pairing). EnsureNodeConnectedAsync (called by ConnectionManagerWindowsNodeConnector
Expand Down Expand Up @@ -289,7 +289,7 @@
if (allowedLocales.Contains(langOverride.ToLowerInvariant()))
LocalizationHelper.SetLanguageOverride(langOverride);
else
Logger.Warn($"[App] Ignoring invalid OPENCLAW_LANGUAGE value: {langOverride}");

Check warning on line 292 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 292 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 292 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 292 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 292 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 292 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}

InitializeComponent();
Expand Down Expand Up @@ -326,7 +326,7 @@
MarkRunEnded();
try
{
Logger.Info($"Process exiting (ExitCode={Environment.ExitCode})");

Check warning on line 329 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 329 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 329 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 329 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}
catch { }
}
Expand All @@ -348,11 +348,11 @@
{
if (ex != null)
{
Logger.Error($"CRASH {source}: {ex}");

Check warning on line 351 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 351 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 351 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 351 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}
else
{
Logger.Error($"CRASH {source}");

Check warning on line 355 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 355 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 355 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}
}
catch { /* Ignore logging failures */ }
Expand Down Expand Up @@ -515,7 +515,7 @@
if (File.Exists(RunMarkerPath))
{
var startedAt = File.ReadAllText(RunMarkerPath);
Logger.Error($"Previous session did not exit cleanly (started {startedAt})");

Check warning on line 518 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
File.Delete(RunMarkerPath);
}
}
Expand Down Expand Up @@ -711,14 +711,45 @@
{
try
{
// A node client was just created (manager auto-start OR setup engine
// EnsureNodeConnectedAsync). We MUST have a NodeService to register
// capabilities on this client before the outbound "connect" goes out —
// see NodeConnector.cs:66. Build it lazily here so we never depend on
// OnLaunched ordering or the _suppressNodeDuringSetup gate having
// landed in the right state. EnsureNodeService is
// idempotent — it returns the existing instance if already built.
// Without this, _nodeService?.AttachClient below is a silent no-op and
// the gateway sees the node with caps=0/cmds=0 (regression introduced
// 2026-05-12 in 62533e2 when capability registration moved to this
// lazy bridge pattern).
if (_settings == null)
{
Logger.Warn("[App] NodeConnector.ClientCreated fired before settings were initialized; node may connect without capabilities");
diagnostics.Record("node", "WARNING: settings unavailable; cannot initialize NodeService for capability binding");
}
else
{
EnsureNodeService(_settings);
}

diagnostics.Record("node", $"ClientCreated fired, _nodeService null={_nodeService is null}");
_nodeService?.AttachClient(args.Client, args.BearerToken);
if (_nodeService == null)
{
Logger.Warn("[App] NodeService unavailable during ClientCreated; node may connect with caps=0/cmds=0");
diagnostics.Record("node", "WARNING: NodeService unavailable; cannot bind node capabilities");
return;
}

_nodeService.AttachClient(args.Client, args.BearerToken);
var client = args.Client;
diagnostics.Record("node", $"After AttachClient: caps={client.Capabilities.Count}, cmds={client.RegisteredCommandCount}");
if (client.RegisteredCommandCount > 0)
diagnostics.Record("node", $"Commands sample: {string.Join(", ", client.RegisteredCommandsSample)}...");
else
{
Logger.Warn("[App] Node capability binding produced 0 commands before connect");
diagnostics.Record("node", "WARNING: 0 commands registered on node client before connect");
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -762,7 +793,7 @@
// The method is idempotent — safe to call here AND later if first-run setup runs.
if (ShouldInitializeNodeService() && _settings != null)
{
EnsureNodeServiceForLocalGatewaySetup(_settings);
EnsureNodeService(_settings);
}

// Initialize connections — always create operator client for UI data,
Expand Down Expand Up @@ -1678,7 +1709,7 @@
return false;
}

var nodeService = EnsureNodeServiceForLocalGatewaySetup(_settings);
var nodeService = EnsureNodeService(_settings);
if (nodeService == null)
{
Logger.Warn("MCP-only mode requested but node service could not be initialized");
Expand Down Expand Up @@ -1779,7 +1810,7 @@
});
}

private NodeService? EnsureNodeServiceForLocalGatewaySetup(SettingsManager settings)
private NodeService? EnsureNodeService(SettingsManager settings)
{
if (_nodeService != null)
return _nodeService;
Expand Down
14 changes: 14 additions & 0 deletions tests/OpenClaw.Connection.Tests/NodeConnectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ public async Task ConnectAsync_AfterDispose_IsNoOp()
Assert.Null(connector.Client);
}

[Fact]
public async Task ConnectAsync_WhenClientCreatedHandlerThrows_RecordsDiagnostic()
{
var diagnostics = new ConnectionDiagnostics();
using var connector = new NodeConnector(new StubLogger(), diagnostics);
connector.ClientCreated += (_, _) => throw new InvalidOperationException("boom");

await connector.ConnectAsync("ws://127.0.0.1:9", new GatewayCredential("tok", false, "test"), "id-path");

var evt = Assert.Single(diagnostics.GetAll(), e => e.Category == "node");
Assert.Equal("ClientCreated handler failed; node may connect without capabilities", evt.Message);
Assert.Equal("boom", evt.Detail);
}

[Fact]
public async Task DisconnectAsync_WhenNotConnected_CompletesWithoutError()
{
Expand Down
Loading