feat: ship agent-first mission control v0.2.57
CI - Build & Test / Backend (.NET) (push) Successful in 42s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m46s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Successful in 56s

This commit is contained in:
AzuTear
2026-07-31 22:39:47 +02:00
parent 3bc7622977
commit f5552218bc
535 changed files with 95242 additions and 8791 deletions
@@ -0,0 +1,132 @@
using System.Text.Json.Nodes;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Nexus.Api.Data;
using Nexus.Api.Repositories;
using Nexus.Api.Services;
using Xunit;
namespace Nexus.Api.Tests;
public sealed class OpenClawEventSubscriptionCoordinatorTests
{
[Fact]
public async Task SynchronizeOnce_SubscribesCatalogAndActiveSessions_OncePerConnection()
{
var services = new ServiceCollection();
var databaseName = $"subscription-{Guid.NewGuid():N}";
services.AddDbContext<NexusDbContext>(options =>
options.UseInMemoryDatabase(databaseName));
services.AddScoped<IOpenClawRunRepository, OpenClawRunRepository>();
await using var provider = services.BuildServiceProvider();
await using (var scope = provider.CreateAsyncScope())
{
var db = scope.ServiceProvider.GetRequiredService<NexusDbContext>();
db.OpenClawRuns.Add(new OpenClawRun
{
Title = "Active run",
Prompt = "Do work",
AgentId = "iris",
SessionKey = "agent:iris:main",
Status = OpenClawRunStates.Running,
StartIdempotencyKey = "subscription-key",
CorrelationId = "subscription-correlation",
Actor = "owner"
});
await db.SaveChangesAsync();
}
var connector = new SubscriptionConnector();
var coordinator = new OpenClawEventSubscriptionCoordinator(
connector,
provider.GetRequiredService<IServiceScopeFactory>(),
NullLogger<OpenClawEventSubscriptionCoordinator>.Instance);
await coordinator.SynchronizeOnceAsync();
await coordinator.SynchronizeOnceAsync();
Assert.Equal(2, connector.Calls.Count);
Assert.Equal("sessions.subscribe", connector.Calls[0].Method);
Assert.Equal("sessions.messages.subscribe", connector.Calls[1].Method);
Assert.Equal("agent:iris:main", connector.Calls[1].Parameters?["key"]?.GetValue<string>());
Assert.Equal("iris", connector.Calls[1].Parameters?["agentId"]?.GetValue<string>());
Assert.True(connector.Calls[1].Parameters?["includeApprovals"]?.GetValue<bool>());
await SetRunStatusAsync(provider, OpenClawRunStates.Completed);
await coordinator.SynchronizeOnceAsync();
Assert.Equal(3, connector.Calls.Count);
Assert.Equal("sessions.messages.unsubscribe", connector.Calls[2].Method);
await SetRunStatusAsync(provider, OpenClawRunStates.Running);
connector.LastConnectedAtValue = connector.LastConnectedAtValue.AddMinutes(1);
await coordinator.SynchronizeOnceAsync();
Assert.Equal(5, connector.Calls.Count);
Assert.Equal("sessions.subscribe", connector.Calls[3].Method);
Assert.Equal("sessions.messages.subscribe", connector.Calls[4].Method);
}
private static async Task SetRunStatusAsync(
ServiceProvider provider,
string status)
{
await using var scope = provider.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<NexusDbContext>();
var run = await db.OpenClawRuns.SingleAsync();
run.Status = status;
await db.SaveChangesAsync();
}
private sealed class SubscriptionConnector : IGatewayConnector
{
public List<SubscriptionCall> Calls { get; } = [];
public DateTimeOffset LastConnectedAtValue { get; set; } = DateTimeOffset.UtcNow;
public GatewayConnectionState ConnectionState => GatewayConnectionState.Connected;
public string? GatewayVersion => "2026.7.0";
public string? RequiredVersion => "2026.7.0";
public DateTimeOffset? LastConnectedAt => LastConnectedAtValue;
public int ReconnectAttempts => 0;
public string? StatusMessage => "Connected";
public string? DeviceId => "nexus-test";
public bool DeviceTokenConfigured => true;
public bool PairingRequired => false;
public string? PairingRequestId => null;
public int? ProtocolVersion => 4;
public IReadOnlySet<string> AdvertisedMethods { get; } = new HashSet<string>(
[
"sessions.subscribe",
"sessions.messages.subscribe",
"sessions.messages.unsubscribe"
],
StringComparer.Ordinal);
public IReadOnlySet<string> AdvertisedEvents { get; } = new HashSet<string>();
public IReadOnlySet<string> GrantedScopes { get; } = new HashSet<string>(
["operator.read", "operator.approvals"],
StringComparer.Ordinal);
public DateTimeOffset? LastEventAt => null;
public bool Supports(string method) => AdvertisedMethods.Contains(method);
public Task<JsonNode?> InvokeAsync(
string method,
object? parameters = null,
TimeSpan? timeout = null,
CancellationToken cancellationToken = default,
OpenClawInvocationContext? invocationContext = null)
{
Calls.Add(new SubscriptionCall(
method,
parameters as JsonNode,
invocationContext));
return Task.FromResult<JsonNode?>(new JsonObject { ["ok"] = true });
}
public IReadOnlyList<GatewayEventEnvelope> GetRecentEvents(int limit = 100) => [];
}
private sealed record SubscriptionCall(
string Method,
JsonNode? Parameters,
OpenClawInvocationContext? Invocation);
}