fix: remediate 10 review findings in communication spine

- Fix createSession race condition with in-flight promise map
- Fix listener leak: always cleanup previous subscription per client
- Fix REST timeout returning HTTP 200 — now rejects with 504
- Fix fire-and-forget Discord sends — await with error handling
- Fix non-null assertion on client.user in Discord plugin
- Fix TUI disconnect mid-stream deadlock (reset streaming state)
- Add connect_error handler to TUI and Discord plugin
- Add connected guard on TUI message submit
- Add relayEvent guard for disconnected sockets
- Sanitize error messages sent to WebSocket clients
- Add error logging/context to AgentService create/prompt/destroy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 20:31:39 -05:00
parent 98380e610d
commit 11d468cf7b
5 changed files with 176 additions and 42 deletions

View File

@@ -32,7 +32,20 @@ export function TuiApp({ gatewayUrl, conversationId: initialConversationId }: Tu
socketRef.current = socket;
socket.on('connect', () => setConnected(true));
socket.on('disconnect', () => setConnected(false));
socket.on('disconnect', () => {
setConnected(false);
setIsStreaming(false);
setCurrentStreamText('');
});
socket.on('connect_error', (err: Error) => {
setMessages((msgs) => [
...msgs,
{
role: 'assistant',
content: `Connection failed: ${err.message}. Check that the gateway is running at ${gatewayUrl}.`,
},
]);
});
socket.on('message:ack', (data: { conversationId: string }) => {
setConversationId(data.conversationId);
@@ -69,7 +82,14 @@ export function TuiApp({ gatewayUrl, conversationId: initialConversationId }: Tu
const handleSubmit = useCallback(
(value: string) => {
if (!value.trim() || isStreaming || !socketRef.current) return;
if (!value.trim() || isStreaming) return;
if (!socketRef.current?.connected) {
setMessages((msgs) => [
...msgs,
{ role: 'assistant', content: 'Not connected to gateway. Message not sent.' },
]);
return;
}
setMessages((msgs) => [...msgs, { role: 'user', content: value }]);
setInput('');