mega-minds
Version:
Enhanced multi-agent workflow system for Claude Code projects with automated handoff management and Claude Code hooks integration
210 lines (180 loc) • 7.8 kB
JavaScript
// lib/commands/record-agent-complete.js
// Command: npx mega-minds record-agent-complete "agent-name" "completion-summary" "next-agent"
// Purpose: Records agent work completion and facilitates handoffs (PRD Core Feature #1)
const AIDevTeam = require('../core/AIDevTeam');
/**
* Records agent completion and manages handoff to next agent
* Implements PRD requirements:
* - Real-Time Agent Coordination with handoff tracking
* - Session state persistence across Claude Code restarts
*/
class AgentCompleteRecorder {
constructor() {
this.projectPath = process.cwd();
}
/**
* Main execution function for recording agent completion
* @param {string} agentName - Name of the agent completing work
* @param {string} completionSummary - Summary of completed work
* @param {string} nextAgent - Optional next agent for handoff
* @returns {Promise<object>} Completion result with metrics
*/
async run(agentName, completionSummary, nextAgent = null) {
if (!agentName) {
console.error('❌ Agent name is required');
console.log('Usage: npx mega-minds record-agent-complete "agent-name" "completion-summary" ["next-agent"]');
process.exit(1);
}
if (!completionSummary) {
console.error('❌ Completion summary is required');
console.log('Usage: npx mega-minds record-agent-complete "agent-name" "completion-summary" ["next-agent"]');
process.exit(1);
}
try {
const team = new AIDevTeam(this.projectPath);
await team.initialize();
// Find all active handoffs for this agent
const activeHandoffs = await team.agentState.getActiveHandoffs();
const agentHandoffs = activeHandoffs.filter(h => h.toAgent === agentName);
if (agentHandoffs.length === 0) {
console.warn(`⚠️ No active handoffs found for ${agentName}`);
console.log('Recording completion without handoff closure.');
}
// Complete all handoffs for this agent
let completedCount = 0;
for (const handoff of agentHandoffs) {
try {
await team.agentState.recordHandoffCompleted(handoff.id, agentName, {
completionSummary,
completionTime: new Date().toISOString(),
nextAgent,
deliverables: this.extractDeliverables(completionSummary),
metrics: {
duration: this.calculateDuration(handoff.timestamp),
success: true
}
});
completedCount++;
} catch (error) {
console.warn(`⚠️ Failed to complete handoff ${handoff.id}: ${error.message}`);
}
}
// Update session with completion event
await team.sessions.trackHandoffEvent('agent_complete', {
agentName,
completionSummary,
nextAgent,
completedHandoffs: completedCount,
timestamp: new Date().toISOString(),
source: 'cli'
});
// If there's a next agent, initiate new handoff
let newHandoffId = null;
if (nextAgent) {
newHandoffId = await this.initiateNextHandoff(team, agentName, nextAgent, completionSummary);
}
// Sync handoff state and save session
await team.sessions.syncHandoffState();
await team.sessions.saveActiveSession();
// Display completion status
console.log(`✅ Agent ${agentName} completed successfully`);
console.log(`📝 Summary: ${completionSummary}`);
console.log(`🔗 Completed ${completedCount} handoff(s)`);
if (nextAgent) {
console.log(`🔄 Handoff initiated to: ${nextAgent}`);
console.log(`🆔 New handoff ID: ${newHandoffId}`);
}
console.log(`💾 Session saved with completion tracking`);
// Check memory status and provide warning if needed
const memoryStatus = team.sessions.getMemoryStatus();
if (memoryStatus.system.status === 'warning') {
console.log(`⚠️ Memory warning: ${memoryStatus.system.heapUsedMB}MB used`);
console.log('Consider running: npx mega-minds memory-cleanup');
} else if (memoryStatus.system.status === 'critical') {
console.log(`🚨 Critical memory: ${memoryStatus.system.heapUsedMB}MB used`);
console.log('Running automatic cleanup...');
await team.sessions.forceMemoryCleanup();
console.log('✅ Memory cleanup completed');
}
return {
success: true,
agentName,
completedHandoffs: completedCount,
newHandoffId,
memoryStatus: memoryStatus.system.status
};
} catch (error) {
console.error(`❌ Failed to record agent completion: ${error.message}`);
if (process.env.MEGA_MINDS_DEBUG) {
console.error('Stack trace:', error.stack);
}
process.exit(1);
}
}
/**
* Initiate handoff to next agent
* @private
*/
async initiateNextHandoff(team, fromAgent, toAgent, context) {
return await team.agentState.recordHandoffInitiated(
fromAgent,
toAgent,
{
taskDescription: `Continue work from ${fromAgent}: ${context}`,
context: context,
priority: 'normal',
timestamp: new Date().toISOString(),
source: 'agent-handoff'
}
);
}
/**
* Extract deliverables from completion summary
* @private
*/
extractDeliverables(summary) {
// Simple extraction - could be enhanced with NLP
const deliverables = [];
// Look for common patterns
const patterns = [
/created?\s+(.+?)(?:\.|,|$)/gi,
/implemented?\s+(.+?)(?:\.|,|$)/gi,
/added?\s+(.+?)(?:\.|,|$)/gi,
/fixed?\s+(.+?)(?:\.|,|$)/gi,
/updated?\s+(.+?)(?:\.|,|$)/gi,
/completed?\s+(.+?)(?:\.|,|$)/gi
];
for (const pattern of patterns) {
const matches = summary.matchAll(pattern);
for (const match of matches) {
if (match[1]) {
deliverables.push(match[1].trim());
}
}
}
return deliverables.length > 0 ? deliverables : [summary];
}
/**
* Calculate duration from start timestamp
* @private
*/
calculateDuration(startTimestamp) {
const start = new Date(startTimestamp);
const end = new Date();
const durationMs = end - start;
// Return duration in seconds
return Math.round(durationMs / 1000);
}
}
/**
* CLI entry point
*/
async function recordAgentComplete(agentName, completionSummary, nextAgent) {
const recorder = new AgentCompleteRecorder();
// Enable debug logging if flag is set
if (process.env.MEGA_MINDS_DEBUG || process.argv.includes('--debug')) {
console.log('🔍 Debug mode enabled');
}
return await recorder.run(agentName, completionSummary, nextAgent);
}
module.exports = { AgentCompleteRecorder, recordAgentComplete };