UNPKG

@codemafia0000/d0

Version:

Claude Multi-Agent Automated Development AI - Revolutionary development environment where multiple AI agents collaborate to automate software development

245 lines (196 loc) â€ĸ 7.74 kB
const fs = require('fs'); const path = require('path'); const { spawn } = require('child_process'); const chalk = require('chalk'); const CONSTANTS = require('../constants'); class MessageDaemon { constructor() { this.intervalId = null; this.isRunning = false; this.checkInterval = 5000; // Check for messages every 5 seconds } start() { if (this.isRunning) { return; } console.log(chalk.blue('🤖 Starting message daemon...')); this.isRunning = true; // Start the message checking loop this.intervalId = setInterval(() => { this.processMessages(); }, this.checkInterval); // Also check immediately setTimeout(() => { this.processMessages(); }, 1000); console.log(chalk.green('✅ Message daemon started - agents will auto-read messages')); } stop() { if (!this.isRunning) { return; } console.log(chalk.yellow('âšī¸ Stopping message daemon...')); if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; } this.isRunning = false; console.log(chalk.gray('Message daemon stopped')); } async processMessages() { try { const inboxDir = CONSTANTS.INBOX_DIR; if (!fs.existsSync(inboxDir)) { return; } // Check each agent's inbox const agents = CONSTANTS.AGENT_ROLES; for (const agent of agents) { await this.processAgentMessages(agent); } } catch (error) { console.error(chalk.red('Error in message daemon:'), error.message); } } async processAgentMessages(agent) { const inboxFile = CONSTANTS.getInboxPath(`${agent}.txt`); const notificationFile = CONSTANTS.getInboxPath(`${agent}_notification.txt`); // Check if agent has unread messages if (!fs.existsSync(notificationFile) || !fs.existsSync(inboxFile)) { return; } try { // Read messages const messages = fs.readFileSync(inboxFile, 'utf8').trim().split('\n').filter(line => line.trim()); const latestMessage = messages[messages.length - 1]; if (!latestMessage) { return; } // Extract the actual message content (remove timestamp) const messageContent = latestMessage.replace(/^\[.*?\]\s*/, ''); console.log(chalk.cyan(`🤖 ${agent.toUpperCase()} auto-processing message: "${messageContent}"`)); // Simulate agent processing the message with Claude CLI await this.invokeAgentClaude(agent, messageContent); // Mark message as read by removing notification if (fs.existsSync(notificationFile)) { fs.unlinkSync(notificationFile); } // Update message status this.updateMessageStatus(agent, 'delivered'); } catch (error) { console.error(chalk.red(`Error processing messages for ${agent}:`), error.message); } } async invokeAgentClaude(agent, message) { try { // Create a context-aware prompt for the agent const agentPrompt = this.buildAgentPrompt(agent, message); // For now, we'll simulate the Claude CLI call // In a real implementation, you would spawn Claude CLI process console.log(chalk.green(`✅ ${agent.toUpperCase()} received and acknowledged: "${message.substring(0, 50)}..."`)); // Simulate agent response (you can enable actual Claude CLI call here) // const claudeProcess = spawn('claude', { // stdio: ['pipe', 'pipe', 'pipe'], // cwd: CONSTANTS.PROJECT_ROOT // }); // For demonstration, we'll create a mock response await this.createAgentResponse(agent, message); } catch (error) { console.error(chalk.red(`Failed to invoke Claude for ${agent}:`), error.message); } } buildAgentPrompt(agent, message) { const specialization = this.getAgentSpecialization(agent); return `You are ${agent.toUpperCase()}, a ${specialization.title}. Role: ${specialization.description} Focus: ${specialization.focus} Tasks: ${specialization.tasks} You have received this message: "${message}" Please acknowledge receipt and provide your response or action plan.`; } getAgentSpecialization(agent) { if (agent === 'president') { return { title: 'Project President', description: 'overseeing project strategy and making high-level decisions', focus: 'Project vision, stakeholder communication, strategic planning', tasks: 'Set project direction, coordinate with team, make key decisions' }; } else if (agent === 'boss') { return { title: 'Technical Manager', description: 'coordinating technical teams and managing development workflow', focus: 'Team coordination, technical leadership, task delegation', tasks: 'Delegate tasks to workers, review progress, provide technical guidance' }; } else if (agent.startsWith('worker')) { const workerIndex = parseInt(agent.replace('worker', '')) - 1; const specializations = CONSTANTS.WORKER_SPECIALIZATIONS; return specializations[workerIndex % specializations.length]; } return { title: 'Agent', description: 'handling assigned tasks', focus: 'Task completion', tasks: 'Complete assigned work' }; } async createAgentResponse(agent, message) { // Create a response log const responseDir = CONSTANTS.getHistoryPath(); if (!fs.existsSync(responseDir)) { fs.mkdirSync(responseDir, { recursive: true }); } const responseFile = path.join(responseDir, 'agent_responses.log'); const timestamp = new Date().toISOString(); const responseEntry = `[${timestamp}] ${agent.toUpperCase()}: Acknowledged "${message.substring(0, 100)}"\n`; fs.appendFileSync(responseFile, responseEntry); // If this is boss receiving from president, delegate to workers if (agent === 'boss' && message.length > 10) { setTimeout(() => { this.handleBossDelegation(message); }, 2000); } } async handleBossDelegation(originalMessage) { console.log(chalk.blue('đŸŽ¯ BOSS delegating tasks to workers...')); // Get available workers const sessionFile = CONSTANTS.SESSIONS_FILE; if (!fs.existsSync(sessionFile)) { return; } const sessions = JSON.parse(fs.readFileSync(sessionFile, 'utf8')); const workers = sessions.sessions.filter(s => s.startsWith('worker')); if (workers.length === 0) { return; } // Delegate to worker1 (you can enhance this to split tasks) const workerMessage = `Task from BOSS: ${originalMessage}\n\nPlease execute this task and report back when complete.`; // Send message to worker1 const { sendMessageToAgent } = require('../communication/message-handler'); setTimeout(() => { sendMessageToAgent('worker1', workerMessage, workers.length); }, 1000); } updateMessageStatus(agent, status) { try { const statusFile = CONSTANTS.MESSAGE_STATUS_FILE; if (!fs.existsSync(statusFile)) { return; } const messageStatus = JSON.parse(fs.readFileSync(statusFile, 'utf8')); // Update the latest message for this agent for (const [messageId, msgData] of Object.entries(messageStatus)) { if (msgData.recipient === agent) { msgData.status = status; msgData.delivered = true; msgData.processedAt = new Date().toISOString(); } } fs.writeFileSync(statusFile, JSON.stringify(messageStatus, null, 2)); } catch (error) { console.error(chalk.yellow('Warning: Could not update message status'), error.message); } } } module.exports = MessageDaemon;