redesign fully scaffolded and web login works

This commit is contained in:
2026-03-17 20:10:47 -04:00
parent b9cc397e05
commit f6bd22a8ef
143 changed files with 17317 additions and 693 deletions

View File

@@ -6,18 +6,24 @@ import type { InboundMessage } from '../types/messages.js';
import { randomUUID } from 'crypto';
import type { ProviderConfig } from '../llm/provider.js';
import type { SessionRegistry, EventSubscriber, Session } from '../events/index.js';
export interface WebSocketHandlerConfig {
authenticator: Authenticator;
providerConfig: ProviderConfig;
sessionRegistry: SessionRegistry;
eventSubscriber: EventSubscriber;
}
/**
* WebSocket channel handler
*
* Handles WebSocket connections for chat and integrates with the event system
* for container-to-client notifications.
*/
export class WebSocketHandler {
private config: WebSocketHandlerConfig;
private sessions = new Map<string, AgentHarness>();
private harnesses = new Map<string, AgentHarness>();
constructor(config: WebSocketHandlerConfig) {
this.config = config;
@@ -94,7 +100,30 @@ export class WebSocketHandler {
try {
await harness.initialize();
this.sessions.set(authContext.sessionId, harness);
this.harnesses.set(authContext.sessionId, harness);
// Register session for event system
// Container endpoint is derived from the MCP server URL (same container, different port)
const containerEventEndpoint = this.getContainerEventEndpoint(authContext.license.mcpServerUrl);
const session: Session = {
userId: authContext.userId,
sessionId: authContext.sessionId,
socket,
channelType: 'websocket',
containerEndpoint: containerEventEndpoint,
connectedAt: new Date(),
};
this.config.sessionRegistry.register(session);
// Subscribe to informational events from user's container
await this.config.eventSubscriber.onSessionConnect(session);
logger.info(
{ userId: authContext.userId, containerEndpoint: containerEventEndpoint },
'Session registered for events'
);
// Send connected message
socket.send(
@@ -145,11 +174,19 @@ export class WebSocketHandler {
// Handle disconnection
socket.on('close', async () => {
logger.info({ sessionId: authContext.sessionId }, 'WebSocket disconnected');
// Unregister from event system
const removedSession = this.config.sessionRegistry.unregister(authContext.sessionId);
if (removedSession) {
await this.config.eventSubscriber.onSessionDisconnect(removedSession);
}
// Cleanup harness
await harness.cleanup();
this.sessions.delete(authContext.sessionId);
this.harnesses.delete(authContext.sessionId);
});
socket.on('error', (error) => {
socket.on('error', (error: any) => {
logger.error({ error, sessionId: authContext.sessionId }, 'WebSocket error');
});
} catch (error) {
@@ -158,4 +195,21 @@ export class WebSocketHandler {
await harness.cleanup();
}
}
/**
* Derive the container's XPUB event endpoint from the MCP server URL.
*
* MCP URL format: http://agent-user-abc123.dexorder-agents.svc.cluster.local:3000
* Event endpoint: tcp://agent-user-abc123.dexorder-agents.svc.cluster.local:5570
*/
private getContainerEventEndpoint(mcpServerUrl: string): string {
try {
const url = new URL(mcpServerUrl);
// Replace protocol and port
return `tcp://${url.hostname}:5570`;
} catch {
// Fallback if URL parsing fails
return mcpServerUrl.replace('http://', 'tcp://').replace(':3000', ':5570');
}
}
}