chore: recovery checkpoint - v3.0 API successfully recovered
CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB Recovery Status: - Successfully recovered brainy.ts from compiled JavaScript - All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.) - Neural subsystem intact (562KB embedded patterns, NLP working) - Augmentation pipeline operational (20+ augmentations) - HNSW clustering system complete - Triple Intelligence compiled (needs constructor fix) - Test suite validates functionality Changes preserved: - 898 files with changes from last 3 days - 144,475 insertions - All augmentation improvements - All test coverage enhancements - Complete v3.0 feature set This is a LOCAL checkpoint only - contains recovered work after corruption incident. Created backup in .backups/brainy-full-20250910-151314.tar.gz Branch: recovery-checkpoint-20250910-151433 Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
parent
f65455fb22
commit
8ff382ca3b
895 changed files with 143654 additions and 28268 deletions
|
|
@ -0,0 +1,303 @@
|
|||
/**
|
||||
* BrainyMCPBroadcast
|
||||
*
|
||||
* Enhanced MCP service with real-time WebSocket broadcasting capabilities
|
||||
* for multi-agent coordination (Jarvis ↔ Picasso communication)
|
||||
*
|
||||
* Features:
|
||||
* - WebSocket server for real-time push notifications
|
||||
* - Subscription management for multiple Claude instances
|
||||
* - Message broadcasting to all connected agents
|
||||
* - Works both locally and with cloud deployment
|
||||
*/
|
||||
import { WebSocketServer, WebSocket } from 'ws';
|
||||
import { createServer } from 'http';
|
||||
import { BrainyMCPService } from './brainyMCPService.js';
|
||||
import { v4 as uuidv4 } from '../universal/uuid.js';
|
||||
export class BrainyMCPBroadcast extends BrainyMCPService {
|
||||
constructor(brainyData, options = {}) {
|
||||
super(brainyData, options);
|
||||
this.agents = new Map();
|
||||
this.messageHistory = [];
|
||||
this.maxHistorySize = 100;
|
||||
}
|
||||
/**
|
||||
* Start the WebSocket broadcast server
|
||||
* @param port Port to listen on (default: 8765)
|
||||
* @param isCloud Whether this is a cloud deployment
|
||||
*/
|
||||
async startBroadcastServer(port = 8765, isCloud = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// Create HTTP server
|
||||
this.httpServer = createServer((req, res) => {
|
||||
// Health check endpoint
|
||||
if (req.url === '/health') {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({
|
||||
status: 'healthy',
|
||||
agents: Array.from(this.agents.values()).map(a => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
role: a.role,
|
||||
connected: true
|
||||
})),
|
||||
uptime: process.uptime()
|
||||
}));
|
||||
}
|
||||
else {
|
||||
res.writeHead(404);
|
||||
res.end('Not found');
|
||||
}
|
||||
});
|
||||
// Create WebSocket server
|
||||
this.wsServer = new WebSocketServer({
|
||||
server: this.httpServer,
|
||||
perMessageDeflate: false // Better performance
|
||||
});
|
||||
this.wsServer.on('connection', (socket, request) => {
|
||||
this.handleNewConnection(socket, request);
|
||||
});
|
||||
// Start listening
|
||||
this.httpServer.listen(port, () => {
|
||||
console.log(`🧠 Brain Jar Broadcast Server running on ${isCloud ? 'cloud' : 'local'} port ${port}`);
|
||||
console.log(`📡 WebSocket: ws://localhost:${port}`);
|
||||
console.log(`🔍 Health: http://localhost:${port}/health`);
|
||||
resolve();
|
||||
});
|
||||
// Heartbeat to keep connections alive
|
||||
setInterval(() => {
|
||||
this.agents.forEach((agent) => {
|
||||
if (Date.now() - agent.lastSeen > 30000) {
|
||||
// Remove inactive agents
|
||||
this.removeAgent(agent.id);
|
||||
}
|
||||
else {
|
||||
// Send heartbeat
|
||||
this.sendToAgent(agent.id, {
|
||||
id: uuidv4(),
|
||||
from: 'server',
|
||||
type: 'heartbeat',
|
||||
data: { timestamp: Date.now() },
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 15000);
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handle new WebSocket connection
|
||||
*/
|
||||
handleNewConnection(socket, request) {
|
||||
const agentId = uuidv4();
|
||||
// Send welcome message
|
||||
socket.send(JSON.stringify({
|
||||
id: uuidv4(),
|
||||
from: 'server',
|
||||
type: 'notification',
|
||||
event: 'welcome',
|
||||
data: {
|
||||
agentId,
|
||||
message: 'Connected to Brain Jar Broadcast Server',
|
||||
agents: Array.from(this.agents.values()).map(a => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
role: a.role
|
||||
}))
|
||||
},
|
||||
timestamp: Date.now()
|
||||
}));
|
||||
// Handle messages from this agent
|
||||
socket.on('message', (data) => {
|
||||
try {
|
||||
const message = JSON.parse(data.toString());
|
||||
this.handleAgentMessage(agentId, message);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Invalid message from agent:', error);
|
||||
}
|
||||
});
|
||||
// Handle disconnection
|
||||
socket.on('close', () => {
|
||||
this.removeAgent(agentId);
|
||||
});
|
||||
// Handle errors
|
||||
socket.on('error', (error) => {
|
||||
console.error(`Agent ${agentId} error:`, error);
|
||||
});
|
||||
// Store temporary connection until identified
|
||||
this.agents.set(agentId, {
|
||||
id: agentId,
|
||||
name: 'Unknown',
|
||||
role: 'Unknown',
|
||||
socket,
|
||||
lastSeen: Date.now()
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handle message from an agent
|
||||
*/
|
||||
handleAgentMessage(agentId, message) {
|
||||
const agent = this.agents.get(agentId);
|
||||
if (!agent)
|
||||
return;
|
||||
// Update last seen
|
||||
agent.lastSeen = Date.now();
|
||||
// Handle identification
|
||||
if (message.type === 'identify') {
|
||||
agent.name = message.name || agent.name;
|
||||
agent.role = message.role || agent.role;
|
||||
// Notify all agents about new member
|
||||
this.broadcast({
|
||||
id: uuidv4(),
|
||||
from: 'server',
|
||||
type: 'notification',
|
||||
event: 'agent_joined',
|
||||
data: {
|
||||
agent: {
|
||||
id: agent.id,
|
||||
name: agent.name,
|
||||
role: agent.role
|
||||
}
|
||||
},
|
||||
timestamp: Date.now()
|
||||
}, agentId); // Exclude the joining agent
|
||||
// Send recent history to new agent
|
||||
if (this.messageHistory.length > 0) {
|
||||
this.sendToAgent(agentId, {
|
||||
id: uuidv4(),
|
||||
from: 'server',
|
||||
type: 'sync',
|
||||
data: {
|
||||
history: this.messageHistory.slice(-20) // Last 20 messages
|
||||
},
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Create broadcast message
|
||||
const broadcastMsg = {
|
||||
id: message.id || uuidv4(),
|
||||
from: agent.name,
|
||||
to: message.to,
|
||||
type: message.type || 'message',
|
||||
event: message.event,
|
||||
data: message.data,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
// Store in history
|
||||
this.addToHistory(broadcastMsg);
|
||||
// Broadcast based on recipient
|
||||
if (message.to) {
|
||||
// Send to specific agent(s)
|
||||
const recipients = Array.isArray(message.to) ? message.to : [message.to];
|
||||
recipients.forEach((recipientName) => {
|
||||
const recipient = Array.from(this.agents.values()).find(a => a.name === recipientName);
|
||||
if (recipient) {
|
||||
this.sendToAgent(recipient.id, broadcastMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Broadcast to all agents except sender
|
||||
this.broadcast(broadcastMsg, agentId);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Broadcast message to all connected agents
|
||||
*/
|
||||
broadcast(message, excludeId) {
|
||||
const messageStr = JSON.stringify(message);
|
||||
this.agents.forEach((agent) => {
|
||||
if (agent.id !== excludeId && agent.socket.readyState === WebSocket.OPEN) {
|
||||
agent.socket.send(messageStr);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Send message to specific agent
|
||||
*/
|
||||
sendToAgent(agentId, message) {
|
||||
const agent = this.agents.get(agentId);
|
||||
if (agent && agent.socket.readyState === WebSocket.OPEN) {
|
||||
agent.socket.send(JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove agent from connected list
|
||||
*/
|
||||
removeAgent(agentId) {
|
||||
const agent = this.agents.get(agentId);
|
||||
if (agent) {
|
||||
// Notify others about disconnection
|
||||
this.broadcast({
|
||||
id: uuidv4(),
|
||||
from: 'server',
|
||||
type: 'notification',
|
||||
event: 'agent_left',
|
||||
data: {
|
||||
agent: {
|
||||
id: agent.id,
|
||||
name: agent.name,
|
||||
role: agent.role
|
||||
}
|
||||
},
|
||||
timestamp: Date.now()
|
||||
});
|
||||
this.agents.delete(agentId);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add message to history
|
||||
*/
|
||||
addToHistory(message) {
|
||||
this.messageHistory.push(message);
|
||||
// Trim history if too large
|
||||
if (this.messageHistory.length > this.maxHistorySize) {
|
||||
this.messageHistory = this.messageHistory.slice(-this.maxHistorySize);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Stop the broadcast server
|
||||
*/
|
||||
async stopBroadcastServer() {
|
||||
// Close all agent connections
|
||||
this.agents.forEach(agent => {
|
||||
agent.socket.close(1000, 'Server shutting down');
|
||||
});
|
||||
this.agents.clear();
|
||||
// Close WebSocket server
|
||||
if (this.wsServer) {
|
||||
this.wsServer.close();
|
||||
}
|
||||
// Close HTTP server
|
||||
if (this.httpServer) {
|
||||
this.httpServer.close();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get connected agents
|
||||
*/
|
||||
getConnectedAgents() {
|
||||
return Array.from(this.agents.values()).map(a => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
role: a.role
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Get message history
|
||||
*/
|
||||
getMessageHistory() {
|
||||
return [...this.messageHistory];
|
||||
}
|
||||
}
|
||||
// Export for both environments
|
||||
export default BrainyMCPBroadcast;
|
||||
//# sourceMappingURL=brainyMCPBroadcast.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue