@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
JavaScript
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;