@codemafia0000/d0
Version:
Claude Multi-Agent Automated Development AI - Revolutionary development environment where multiple AI agents collaborate to automate software development
1,509 lines (1,266 loc) • 106 kB
JavaScript
#!/usr/bin/env node
const { Command } = require('commander');
const chalk = require('chalk');
const ora = require('ora');
const fs = require('fs');
const path = require('path');
const { execSync, spawn } = require('child_process');
const os = require('os');
const program = new Command();
// Read version from package.json
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
// Version information
program
.name('d0')
.description('Claude Multi-Agent Automated Development AI - Revolutionary collaborative AI development environment')
.version(packageJson.version);
// Global configuration
const CONFIG_DIR = path.join(os.homedir(), '.d0');
const PROJECT_TEMPLATE_DIR = path.join(__dirname, '..', 'templates');
// Helper functions
function ensureConfigDir() {
if (!fs.existsSync(CONFIG_DIR)) {
fs.mkdirSync(CONFIG_DIR, { recursive: true });
}
}
// Setup project function (shared by init and setup commands)
async function setupProject(options) {
const spinner = ora('Setting up Claude agents environment...').start();
try {
// Validate number of workers
const numWorkers = parseInt(options.workers, 10);
if (isNaN(numWorkers) || numWorkers < 1 || numWorkers > 10) {
spinner.fail('Number of workers must be between 1 and 10');
process.exit(1);
}
// Check prerequisites (Claude CLI only, no tmux required)
spinner.text = 'Checking prerequisites...';
if (!checkClaudeCLI()) {
spinner.fail('Claude CLI is not installed. Please install Claude CLI first.');
console.log(chalk.yellow('Install Claude CLI: https://docs.anthropic.com/en/docs/claude-code'));
process.exit(1);
}
// Create .d0 directory first
const currentDir = process.cwd();
const d0Dir = path.join(currentDir, '.d0');
// Handle existing .d0 (file or directory)
if (fs.existsSync(d0Dir)) {
const stats = fs.statSync(d0Dir);
if (stats.isFile()) {
// Remove existing .d0 file to create directory
fs.unlinkSync(d0Dir);
fs.mkdirSync(d0Dir);
} else if (stats.isDirectory()) {
// Directory already exists, that's fine
}
} else {
fs.mkdirSync(d0Dir);
}
// Check and setup Claude CLI authentication (shared across all agents)
spinner.text = 'Setting up Claude CLI authentication...';
const claudeConfigDir = path.join(d0Dir, 'claude');
if (!fs.existsSync(claudeConfigDir)) {
fs.mkdirSync(claudeConfigDir, { recursive: true });
}
let claudeAuth = false;
try {
// Try to run a simple claude command to check auth status with timeout
execSync('claude auth status', { stdio: 'ignore', timeout: 5000 });
claudeAuth = true;
spinner.text = 'Claude CLI already authenticated';
// Copy Claude config to project for sharing
const homeClaudeDir = path.join(os.homedir(), '.claude');
if (fs.existsSync(homeClaudeDir)) {
fs.cpSync(homeClaudeDir, claudeConfigDir, { recursive: true, force: true });
spinner.text = 'Claude CLI configuration shared with project';
}
} catch {
claudeAuth = false;
spinner.warn('Claude CLI authentication required');
console.log(chalk.yellow('\n⚠️ Setting up Claude CLI authentication...'));
console.log(chalk.blue('This will open your browser for one-time authentication.'));
try {
// Use spawn for interactive auth
const authProcess = spawn('claude', ['auth', 'login'], {
stdio: 'inherit'
});
// Wait for auth process to complete
await new Promise((resolve, reject) => {
authProcess.on('exit', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Authentication failed with code ${code}`));
}
});
});
// Copy the new authentication to project
const homeClaudeDir = path.join(os.homedir(), '.claude');
if (fs.existsSync(homeClaudeDir)) {
fs.cpSync(homeClaudeDir, claudeConfigDir, { recursive: true, force: true });
spinner.text = 'Authentication completed and shared';
claudeAuth = true;
}
} catch (authError) {
spinner.warn('Authentication setup failed');
console.log(chalk.yellow('\n⚠️ Manual setup required:'));
console.log(chalk.gray('Please run: claude auth login'));
console.log(chalk.gray('Then run: d0 init again'));
}
}
// Check existing project
if (isProjectSetup() && !options.force) {
spinner.fail('Claude agents environment already exists in this directory.');
console.log(chalk.yellow('Use --force to overwrite existing setup.'));
process.exit(1);
}
spinner.text = 'Copying template files...';
// Copy template files
const templatePath = path.join(__dirname, '..', 'templates');
// Copy main files
const filesToCopy = [
'CLAUDE.md'
];
for (const file of filesToCopy) {
const srcPath = path.join(templatePath, file);
const destPath = path.join(currentDir, file);
if (fs.existsSync(srcPath)) {
fs.copyFileSync(srcPath, destPath);
console.log(` ✓ Copied ${file}`);
}
}
// .d0 directory already created above
// Create tmp subdirectory
const setupTmpDir = path.join(d0Dir, 'tmp');
if (!fs.existsSync(setupTmpDir)) {
fs.mkdirSync(setupTmpDir);
}
// Create instructions subdirectory and copy instructions files
const instructionsDir = path.join(d0Dir, 'instructions');
if (!fs.existsSync(instructionsDir)) {
fs.mkdirSync(instructionsDir);
}
// Copy instructions files to .d0/instructions/
const templateInstructionsPath = path.join(__dirname, '..', 'templates', 'instructions');
if (fs.existsSync(templateInstructionsPath)) {
fs.cpSync(templateInstructionsPath, instructionsDir, { recursive: true, force: true });
}
// Dynamic files are no longer needed - using file-based communication
fs.writeFileSync(path.join(d0Dir, 'config.json'), JSON.stringify({
created: new Date().toISOString(),
version: '1.0.0',
workers: numWorkers
}, null, 2));
// Legacy marker is not needed since we're using the .d0 directory structure
// The directory itself serves as the project marker
// Initialize history management
getHistoryDir();
hookAgentCommunication();
// Update .gitignore to exclude temporary files
const gitignoreUpdated = updateGitignore(currentDir);
// Log session start
await logSessionEvent('setup', { type: 'basic' });
spinner.succeed('Claude agents environment setup completed!');
console.log(chalk.green('\n✅ Setup completed successfully!'));
if (gitignoreUpdated) {
console.log(chalk.blue('📝 Updated .gitignore to exclude temporary files'));
}
// Setup shell completion
await setupShellCompletion();
console.log(chalk.green('\n🔧 Configuration complete:'));
console.log(chalk.gray(' • Claude CLI authentication: ') + (claudeAuth ? chalk.green('✓ Configured') : chalk.yellow('⚠ Requires manual setup')));
console.log(chalk.gray(' • Agent configuration: ') + chalk.green('✓ Ready'));
console.log(chalk.gray(' • Communication system: ') + chalk.green('✓ Initialized'));
console.log(chalk.yellow('\n🚀 Ready to start:'));
console.log(chalk.blue(' d0 start') + chalk.gray(' - Launch all agents automatically'));
console.log(chalk.gray('\nThen:'));
console.log(chalk.blue(' d0 tell "Create a todo app"') + chalk.gray(' - Start your first project'));
} catch (error) {
spinner.fail('Setup failed');
console.error(chalk.red(error.message));
process.exit(1);
}
}
function updateGitignore(projectDir) {
const gitignorePath = path.join(projectDir, '.gitignore');
// Define what should be ignored in .d0 directory
const d0IgnoreEntries = [
'',
'# Claude Agents - temporary and local files',
'.d0/tmp/',
'.d0/history/',
'# Keep config.json and instructions but ignore sensitive data',
'# .d0/config.json # Uncomment this line if config contains sensitive data',
'# .d0/instructions/ # Uncomment this line if you want to exclude instructions from git',
''
];
let gitignoreContent = '';
// Read existing .gitignore if it exists
if (fs.existsSync(gitignorePath)) {
gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
}
// Check if our entries already exist
const hasD0Entries = gitignoreContent.includes('# Claude Agents - temporary and local files');
if (!hasD0Entries) {
// Add our entries to .gitignore
if (gitignoreContent && !gitignoreContent.endsWith('\n')) {
gitignoreContent += '\n';
}
gitignoreContent += d0IgnoreEntries.join('\n');
fs.writeFileSync(gitignorePath, gitignoreContent);
return true; // Indicates .gitignore was updated
}
return false; // No update needed
}
// Setup shell completion automatically
async function setupShellCompletion() {
try {
// Detect user's shell
const userShell = process.env.SHELL || '';
let shellType = '';
if (userShell.includes('bash')) {
shellType = 'bash';
} else if (userShell.includes('zsh')) {
shellType = 'zsh';
} else {
// Skip automatic setup for unknown shells
console.log(chalk.blue('\n💡 Shell completion available:'));
console.log(chalk.gray(' Run: d0 completion bash (for Bash)'));
console.log(chalk.gray(' Run: d0 completion zsh (for Zsh)'));
return;
}
console.log(chalk.blue(`\n🔧 Setting up ${shellType} completion...`));
const completionDir = path.join(__dirname, '..', 'completions');
const homeDir = os.homedir();
if (shellType === 'bash') {
const bashCompletionSource = path.join(completionDir, 'd0-completion.bash');
const bashCompletionTarget = path.join(homeDir, '.bash_completion.d', 'd0');
// Check if completion is already installed
if (fs.existsSync(bashCompletionTarget)) {
console.log(chalk.blue(' ℹ️ Bash completion already installed'));
return;
}
// Create .bash_completion.d directory if it doesn't exist
const bashCompletionDir = path.join(homeDir, '.bash_completion.d');
if (!fs.existsSync(bashCompletionDir)) {
fs.mkdirSync(bashCompletionDir, { recursive: true });
}
// Copy completion script
fs.copyFileSync(bashCompletionSource, bashCompletionTarget);
console.log(chalk.green(' ✅ Bash completion installed'));
console.log(chalk.yellow(' 💡 To activate: source ~/.bash_completion.d/d0'));
console.log(chalk.gray(' Or restart your terminal'));
} else if (shellType === 'zsh') {
const zshCompletionSource = path.join(completionDir, '_d0');
// Find zsh completion directory
let zshCompletionDir = '';
const zshDirs = [
'/opt/homebrew/share/zsh/site-functions',
'/usr/local/share/zsh/site-functions',
path.join(homeDir, '.oh-my-zsh', 'custom', 'completions'),
path.join(homeDir, '.zsh', 'completions')
];
// Check if completion is already installed in any of these directories
let alreadyInstalled = false;
for (const dir of zshDirs) {
const targetPath = path.join(dir, '_d0');
if (fs.existsSync(targetPath)) {
console.log(chalk.blue(' ℹ️ Zsh completion already installed'));
alreadyInstalled = true;
break;
}
}
if (alreadyInstalled) {
return;
}
// Find writable directory for installation
for (const dir of zshDirs) {
if (fs.existsSync(dir)) {
zshCompletionDir = dir;
break;
}
}
if (!zshCompletionDir) {
// Create custom completion directory
zshCompletionDir = path.join(homeDir, '.zsh', 'completions');
fs.mkdirSync(zshCompletionDir, { recursive: true });
}
const zshCompletionTarget = path.join(zshCompletionDir, '_d0');
fs.copyFileSync(zshCompletionSource, zshCompletionTarget);
console.log(chalk.green(' ✅ Zsh completion installed'));
console.log(chalk.yellow(` 💡 To activate: Add to ~/.zshrc:`));
console.log(chalk.blue(` fpath=(${zshCompletionDir} $fpath)`));
console.log(chalk.blue(' autoload -U compinit && compinit'));
console.log(chalk.gray(' Or restart your terminal'));
}
} catch (error) {
console.log(chalk.yellow('\n⚠️ Could not setup shell completion automatically'));
console.log(chalk.gray(`Error: ${error.message}`));
console.log(chalk.blue('💡 You can setup completion manually:'));
console.log(chalk.gray(' d0 completion bash (for Bash)'));
console.log(chalk.gray(' d0 completion zsh (for Zsh)'));
}
}
// Send message directly to agent (Node.js version)
function sendMessageToAgent(recipient, message, numWorkers = 3) {
const timestamp = new Date().toISOString();
// Log the message to .d0/history
const historyDir = getHistoryDir();
const logMessage = `[${timestamp}] TO ${recipient}: ${message}`;
const logFile = path.join(historyDir, 'agent_messages.log');
try {
fs.appendFileSync(logFile, logMessage + '\n');
} catch (error) {
console.warn(chalk.yellow(`Warning: Could not log message: ${error.message}`));
}
// Check if sessions are active
const sessionFile = path.join(process.cwd(), '.d0', 'tmp', 'sessions.json');
if (!fs.existsSync(sessionFile)) {
console.error(chalk.red('❌ No active sessions found. Run "d0 start" first.'));
return false;
}
// Validate recipient
const sessionInfo = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));
if (!sessionInfo.sessions.includes(recipient.toLowerCase())) {
console.error(chalk.red(`❌ Unknown recipient: ${recipient}`));
console.log(chalk.yellow('Available recipients:'), sessionInfo.sessions.join(', '));
return false;
}
// For Node.js version, we simulate message delivery
const displayName = recipient.toUpperCase();
try {
console.log(chalk.blue(`📤 Sending to ${displayName}...`));
// Write message to agent's inbox for them to see when they connect
const agentInboxDir = path.join(process.cwd(), '.d0', 'tmp', 'inbox');
if (!fs.existsSync(agentInboxDir)) {
fs.mkdirSync(agentInboxDir, { recursive: true });
}
const inboxFile = path.join(agentInboxDir, `${recipient.toLowerCase()}.txt`);
const messageEntry = `[${timestamp}] ${message}\n`;
fs.appendFileSync(inboxFile, messageEntry);
// Create notification marker for agent communication
const notificationFile = path.join(agentInboxDir, `${recipient.toLowerCase()}_notification.txt`);
fs.writeFileSync(notificationFile, timestamp);
// Create communication status tracking
const statusFile = path.join(process.cwd(), '.d0', 'tmp', 'message_status.json');
let messageStatus = {};
if (fs.existsSync(statusFile)) {
try {
messageStatus = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
} catch (e) {
messageStatus = {};
}
}
const messageId = `${timestamp}_${recipient}`;
messageStatus[messageId] = {
recipient,
message: message.substring(0, 100) + (message.length > 100 ? '...' : ''),
timestamp,
status: 'sent',
delivered: false
};
fs.writeFileSync(statusFile, JSON.stringify(messageStatus, null, 2));
console.log(chalk.green(`✅ Message sent to ${displayName}`));
console.log(chalk.gray(`💡 Agent will see message when they connect with: d0 hi ${recipient.toLowerCase()}`));
// Show enhanced communication tips for different delegation paths
if (recipient.toLowerCase() === 'boss') {
console.log(chalk.yellow('\n💡 Communication Tips:'));
console.log(chalk.gray(' • Boss will delegate tasks to workers automatically'));
console.log(chalk.gray(' • Use specific deliverables and deadlines for best results'));
console.log(chalk.gray(' • Boss will report progress back to you'));
} else if (recipient.toLowerCase().startsWith('worker')) {
console.log(chalk.yellow('\n💡 Worker Communication Tips:'));
console.log(chalk.gray(' • Include specific task requirements and deadlines'));
console.log(chalk.gray(' • Worker will report progress every 30 minutes'));
console.log(chalk.gray(' • Specify working directory and deliverable files'));
console.log(chalk.gray(' • Worker will notify boss upon completion'));
}
return true;
} catch (error) {
console.error(chalk.red(`❌ Failed to send to ${displayName}: ${error.message}`));
return false;
}
}
// Dynamic file generation
async function generateDynamicFiles(numWorkers, projectDir) {
// Generate worker instructions
const instructionsDir = path.join(projectDir, '.d0', 'instructions');
for (let i = 1; i <= numWorkers; i++) {
const workerInstruction = generateWorkerInstruction(i);
fs.writeFileSync(path.join(instructionsDir, `worker${i}.md`), workerInstruction);
}
// Update CLAUDE.md dynamically
updateClaudeConfig(numWorkers, projectDir);
}
// Worker specialization definition
function getWorkerSpecialization(workerNum) {
const specializations = [
{
title: 'Frontend Developer',
emoji: '🎨',
description: 'creating beautiful and responsive user interfaces, implementing UI/UX designs, and optimizing frontend performance',
focus: 'UI/UX, React/Vue/Angular, CSS/SCSS, responsive design, accessibility',
tasks: 'Build components, implement designs, optimize performance, handle user interactions'
},
{
title: 'Backend Developer',
emoji: '⚙️',
description: 'developing robust server-side logic, APIs, and database integrations',
focus: 'REST/GraphQL APIs, databases, authentication, server architecture, performance optimization',
tasks: 'Create APIs, design databases, implement business logic, handle security'
},
{
title: 'DevOps Engineer',
emoji: '🚀',
description: 'managing infrastructure, deployments, and continuous integration/delivery pipelines',
focus: 'CI/CD, Docker, cloud platforms (AWS/GCP/Azure), monitoring, automation',
tasks: 'Setup deployment pipelines, configure infrastructure, monitor applications, automate processes'
},
{
title: 'QA Engineer',
emoji: '🧪',
description: 'ensuring code quality through comprehensive testing and quality assurance',
focus: 'automated testing, test frameworks, quality assurance, performance testing',
tasks: 'Write tests, perform QA, setup test automation, validate functionality'
},
{
title: 'Data Engineer',
emoji: '📊',
description: 'handling data processing, analytics, and machine learning implementations',
focus: 'data pipelines, analytics, ML/AI, data visualization, ETL processes',
tasks: 'Process data, create analytics, implement ML models, build data pipelines'
},
{
title: 'Mobile Developer',
emoji: '📱',
description: 'creating native and cross-platform mobile applications',
focus: 'React Native, Flutter, iOS/Android, mobile UI/UX, app store deployment',
tasks: 'Build mobile apps, implement mobile-specific features, optimize for mobile platforms'
},
{
title: 'Security Engineer',
emoji: '🛡️',
description: 'implementing security measures and ensuring application safety',
focus: 'security audits, vulnerability assessment, secure coding, authentication/authorization',
tasks: 'Perform security reviews, implement security measures, audit code for vulnerabilities'
},
{
title: 'Database Specialist',
emoji: '🗄️',
description: 'designing and optimizing database systems and data architecture',
focus: 'database design, query optimization, data modeling, database administration',
tasks: 'Design schemas, optimize queries, manage data migrations, ensure data integrity'
},
{
title: 'Integration Specialist',
emoji: '🔗',
description: 'integrating third-party services and managing system interconnections',
focus: 'API integrations, webhooks, microservices, service mesh, external APIs',
tasks: 'Integrate external services, manage API connections, ensure system interoperability'
},
{
title: 'Performance Engineer',
emoji: '⚡',
description: 'optimizing application performance and monitoring system efficiency',
focus: 'performance optimization, monitoring, profiling, caching strategies, load testing',
tasks: 'Optimize performance, setup monitoring, analyze bottlenecks, implement caching'
}
];
// Return specialization based on worker number (cycle through if more than 10 workers)
return specializations[(workerNum - 1) % specializations.length];
}
// Worker instruction generation
function generateWorkerInstruction(workerNum) {
const specialization = getWorkerSpecialization(workerNum);
return `# ${specialization.emoji} worker${workerNum} Instructions - ${specialization.title}
## Your Role
As worker${workerNum}, you are a **${specialization.title}** specialist responsible for ${specialization.description}.
## Execution Flow After Receiving Instructions from BOSS
1. **Task Understanding (within 5 minutes)**
- Confirm requirements, ask questions immediately for unclear points
- Understand success criteria numerically
- Confirm dependencies
2. **Implementation Plan Creation (within 10 minutes)**
- Break down task into subtasks
- Estimate effort for each subtask
- Include test plan
3. **Start Implementation**
- Follow coding conventions
- Record progress every 30 minutes
- Report blockers immediately
4. **Completion Report**
- List deliverables
- Attach test results
- Propose next actions
## Communication
Send messages to other agents using:
\`\`\`bash
./agent-send.sh boss "Your message"
./agent-send.sh president "Direct message to president"
\`\`\`
## Your Specialization: ${specialization.title}
**Focus Areas**: ${specialization.focus}
**Primary Responsibilities**:
${specialization.tasks}
## Work Approach
1. **Stay in your lane**: Focus on your specialization area
2. **Collaborate actively**: Coordinate with other specialists
3. **Quality first**: Maintain high standards in your domain
4. **Document decisions**: Explain technical choices clearly
## Collaboration Guidelines
- **With Frontend**: Ensure proper API contracts and data formats
- **With Backend**: Coordinate on data structures and endpoints
- **With DevOps**: Align on deployment and environment needs
- **With QA**: Provide testable implementations
- **With other specialists**: Share insights and coordinate dependencies
## Success Metrics
1. **Specialization Excellence**: Deep expertise in your domain
2. **Integration Success**: Seamless work with other specialists
3. **Quality Delivery**: High-standard outputs with proper documentation
4. **Communication**: Clear progress updates and technical discussions
---
*Generated by Claude Agents v1.0.0*
`;
}
// Update CLAUDE.md configuration
function updateClaudeConfig(numWorkers, projectDir) {
let workerList = '';
for (let i = 1; i <= numWorkers; i++) {
const spec = getWorkerSpecialization(i);
workerList += `- **${spec.emoji} worker${i}** (multiagent:0.${i}): ${spec.title} - ${spec.description}\n`;
}
let roleInstructions = '';
for (let i = 1; i <= numWorkers; i++) {
const spec = getWorkerSpecialization(i);
roleInstructions += `- **${spec.emoji} worker${i}**: @.d0/instructions/worker${i}.md (${spec.title})\n`;
}
const claudeConfig = `# Agent Communication System
## Agent Configuration
- **PRESIDENT** (separate session): Project manager and overall supervisor
- **boss** (multiagent:0.0): Team leader and tech lead
${workerList}## Your Role
- **PRESIDENT**: @.d0/instructions/president.md
- **boss**: @.d0/instructions/boss.md
${roleInstructions}## Message Sending
\`\`\`bash
d0 tell [recipient] "[message]"
# Or use the script directly:
./agent-send.sh [recipient] "[message]"
\`\`\`
## Basic Flow
PRESIDENT → boss → workers → boss → PRESIDENT
`;
const claudePath = path.join(projectDir, 'CLAUDE.md');
// Check if CLAUDE.md already exists
if (fs.existsSync(claudePath)) {
// Read existing content
const existingContent = fs.readFileSync(claudePath, 'utf8');
// Check if our agent configuration already exists
if (existingContent.includes('# Agent Communication System')) {
// Replace the existing agent configuration section
const lines = existingContent.split('\n');
let startIndex = -1;
let endIndex = -1;
for (let i = 0; i < lines.length; i++) {
if (lines[i].includes('# Agent Communication System')) {
startIndex = i;
}
if (startIndex !== -1 && lines[i].trim() === '' && i > startIndex + 5) {
endIndex = i;
break;
}
}
if (startIndex !== -1) {
// Replace the section
const beforeSection = lines.slice(0, startIndex);
const afterSection = endIndex !== -1 ? lines.slice(endIndex + 1) : [];
const newContent = beforeSection.join('\n') + '\n' + claudeConfig + '\n' + afterSection.join('\n');
fs.writeFileSync(claudePath, newContent.trim());
} else {
// Append if no clear section found
fs.appendFileSync(claudePath, '\n\n' + claudeConfig);
}
} else {
// Append to existing file
fs.appendFileSync(claudePath, '\n\n' + claudeConfig);
}
} else {
// Create new file
fs.writeFileSync(claudePath, claudeConfig);
}
}
function isProjectSetup() {
// Check for new directory structure first
if (fs.existsSync('./.d0')) {
const stats = fs.statSync('./.d0');
if (stats.isDirectory()) {
return true; // New structure with .d0 directory
} else if (stats.isFile()) {
return true; // Legacy structure with .d0 file
}
}
// Fall back to checking other markers
return fs.existsSync('./CLAUDE.md') ||
fs.existsSync('./instructions') ||
fs.existsSync('./.d0/instructions');
}
function getProjectConfig() {
// Try new config location first
const newConfigPath = path.join(process.cwd(), '.d0', 'config.json');
if (fs.existsSync(newConfigPath)) {
return JSON.parse(fs.readFileSync(newConfigPath, 'utf8'));
}
// Fall back to legacy location
const legacyConfigPath = path.join(process.cwd(), '.d0');
if (fs.existsSync(legacyConfigPath)) {
try {
const content = fs.readFileSync(legacyConfigPath, 'utf8');
if (content.trim()) {
return JSON.parse(content);
}
} catch {
// If parsing fails, return default config
}
}
// Default config
return { workers: 3, version: '1.0.0' };
}
// Analyze project structure and determine agent roles
function analyzeProjectStructure(projectPath = process.cwd()) {
const analysis = {
hasBackend: false,
hasFrontend: false,
hasDatabase: false,
hasMobile: false,
hasDevOps: false,
hasAI: false,
hasDesign: false,
technologies: [],
projectType: 'general',
suggestedRoles: []
};
try {
// Parse package.json
const packageJsonPath = path.join(projectPath, 'package.json');
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
// Detect frontend technologies
if (dependencies.react || dependencies.vue || dependencies.angular || dependencies.svelte) {
analysis.hasFrontend = true;
analysis.technologies.push('Frontend');
}
// Detect backend technologies
if (dependencies.express || dependencies.fastify || dependencies.koa || dependencies.nest) {
analysis.hasBackend = true;
analysis.technologies.push('Backend');
}
// Detect database technologies
if (dependencies.mongoose || dependencies.sequelize || dependencies.prisma || dependencies.mysql2) {
analysis.hasDatabase = true;
analysis.technologies.push('Database');
}
// Detect mobile technologies
if (dependencies['react-native'] || dependencies['@ionic/angular'] || dependencies.expo) {
analysis.hasMobile = true;
analysis.technologies.push('Mobile');
}
// Detect AI/ML technologies
if (dependencies.tensorflow || dependencies.pytorch || dependencies['@anthropic-ai/sdk'] || dependencies.openai) {
analysis.hasAI = true;
analysis.technologies.push('AI/ML');
}
}
// Analyze file structure
const files = fs.readdirSync(projectPath);
// Detect DevOps/infrastructure files
if (files.includes('Dockerfile') || files.includes('docker-compose.yml') ||
files.includes('.github') || files.includes('terraform') || files.includes('k8s')) {
analysis.hasDevOps = true;
analysis.technologies.push('DevOps');
}
// Detect design files
if (files.some(f => f.includes('design') || f.includes('figma') || f.includes('assets'))) {
analysis.hasDesign = true;
analysis.technologies.push('Design');
}
// Determine project type
if (analysis.hasFrontend && analysis.hasBackend) {
analysis.projectType = 'fullstack';
} else if (analysis.hasFrontend) {
analysis.projectType = 'frontend';
} else if (analysis.hasBackend) {
analysis.projectType = 'backend';
} else if (analysis.hasMobile) {
analysis.projectType = 'mobile';
} else if (analysis.hasAI) {
analysis.projectType = 'ai';
}
// Decide suggested roles
analysis.suggestedRoles = generateSuggestedRoles(analysis);
} catch (error) {
console.warn('Warning: Could not fully analyze project structure:', error.message);
}
return analysis;
}
// Generate suggested roles from project analysis results
function generateSuggestedRoles(analysis) {
const roles = [];
if (analysis.hasFrontend) {
roles.push({
name: 'frontend',
displayName: 'Frontend Developer',
emoji: '🎨',
description: 'UI/UX implementation specialist focusing on user interface development'
});
}
if (analysis.hasBackend) {
roles.push({
name: 'backend',
displayName: 'Backend Developer',
emoji: '⚙️',
description: 'Server-side development specialist focusing on APIs and business logic'
});
}
if (analysis.hasDatabase) {
roles.push({
name: 'database',
displayName: 'Database Engineer',
emoji: '🗄️',
description: 'Database design and optimization specialist'
});
}
if (analysis.hasDevOps) {
roles.push({
name: 'devops',
displayName: 'DevOps Engineer',
emoji: '🚀',
description: 'Infrastructure and deployment automation specialist'
});
}
if (analysis.hasMobile) {
roles.push({
name: 'mobile',
displayName: 'Mobile Developer',
emoji: '📱',
description: 'Mobile application development specialist'
});
}
if (analysis.hasAI) {
roles.push({
name: 'ai',
displayName: 'AI Engineer',
emoji: '🧠',
description: 'Artificial intelligence and machine learning specialist'
});
}
if (analysis.hasDesign) {
roles.push({
name: 'designer',
displayName: 'UX/UI Designer',
emoji: '🎯',
description: 'User experience and interface design specialist'
});
}
// Always add at least a test role
roles.push({
name: 'tester',
displayName: 'Quality Assurance',
emoji: '🔍',
description: 'Quality assurance and testing specialist'
});
return roles;
}
// History management functions
function getHistoryDir() {
const d0Dir = path.join(process.cwd(), '.d0');
const historyDir = path.join(d0Dir, 'history');
if (!fs.existsSync(d0Dir)) {
fs.mkdirSync(d0Dir, { recursive: true });
}
if (!fs.existsSync(historyDir)) {
fs.mkdirSync(historyDir, { recursive: true });
}
return historyDir;
}
async function logAgentMessage(from, to, message) {
const historyDir = getHistoryDir();
const messageLog = {
timestamp: new Date().toISOString(),
from,
to,
message,
type: 'message'
};
const logFile = path.join(historyDir, 'messages.jsonl');
fs.appendFileSync(logFile, JSON.stringify(messageLog) + '\n');
}
async function logTaskAction(action, agent, task, details = '') {
const historyDir = getHistoryDir();
const taskLog = {
timestamp: new Date().toISOString(),
action, // start, complete, block, progress
agent,
task,
details,
type: 'task'
};
const logFile = path.join(historyDir, 'tasks.jsonl');
fs.appendFileSync(logFile, JSON.stringify(taskLog) + '\n');
}
async function logSessionEvent(event, details = {}) {
const historyDir = getHistoryDir();
const sessionLog = {
timestamp: new Date().toISOString(),
event, // start, stop, agent_join, agent_leave
details,
type: 'session'
};
const logFile = path.join(historyDir, 'sessions.jsonl');
fs.appendFileSync(logFile, JSON.stringify(sessionLog) + '\n');
}
async function logProgress(agent, taskId, progress, description = '') {
const historyDir = getHistoryDir();
const progressLog = {
timestamp: new Date().toISOString(),
agent,
taskId,
progress, // 0-100
description,
type: 'progress'
};
const logFile = path.join(historyDir, 'progress.jsonl');
fs.appendFileSync(logFile, JSON.stringify(progressLog) + '\n');
}
async function getProjectHistory(type = 'all', agent = null, days = 7) {
const historyDir = getHistoryDir();
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
let history = {
messages: [],
tasks: [],
sessions: [],
progress: []
};
const logTypes = type === 'all' ? ['messages', 'tasks', 'sessions', 'progress'] : [type];
for (const logType of logTypes) {
const logFile = path.join(historyDir, `${logType}.jsonl`);
if (fs.existsSync(logFile)) {
const lines = fs.readFileSync(logFile, 'utf8').split('\n').filter(line => line.trim());
const logs = lines
.map(line => {
try {
return JSON.parse(line);
} catch {
return null;
}
})
.filter(log => log && new Date(log.timestamp) > cutoffDate)
.filter(log => !agent || log.agent === agent || log.from === agent || log.to === agent);
history[logType] = logs;
}
}
return history;
}
function displayHistory(history, type) {
console.log(chalk.blue(`📚 Project History (${type})\n`));
if (type === 'all' || type === 'messages') {
console.log(chalk.yellow('💬 Messages:'));
history.messages.slice(-10).forEach(msg => {
const time = new Date(msg.timestamp).toLocaleString();
console.log(chalk.gray(` ${time} ${chalk.cyan(msg.from)} → ${chalk.green(msg.to)}`));
console.log(chalk.gray(` ${msg.message.substring(0, 80)}${msg.message.length > 80 ? '...' : ''}`));
});
console.log();
}
if (type === 'all' || type === 'tasks') {
console.log(chalk.yellow('📋 Tasks:'));
history.tasks.slice(-10).forEach(task => {
const time = new Date(task.timestamp).toLocaleString();
const actionEmoji = {
start: '🟡',
complete: '✅',
block: '🔴',
progress: '🔄'
}[task.action] || '⚪';
console.log(chalk.gray(` ${time} ${actionEmoji} ${chalk.cyan(task.agent)} - ${task.task}`));
if (task.details) {
console.log(chalk.gray(` ${task.details}`));
}
});
console.log();
}
if (type === 'all' || type === 'sessions') {
console.log(chalk.yellow('🎮 Sessions:'));
history.sessions.slice(-10).forEach(session => {
const time = new Date(session.timestamp).toLocaleString();
console.log(chalk.gray(` ${time} ${session.event}`));
if (session.details && Object.keys(session.details).length > 0) {
console.log(chalk.gray(` ${JSON.stringify(session.details)}`));
}
});
console.log();
}
if (type === 'all' || type === 'progress') {
console.log(chalk.yellow('📊 Progress:'));
history.progress.slice(-10).forEach(prog => {
const time = new Date(prog.timestamp).toLocaleString();
const progressBar = '█'.repeat(Math.floor(prog.progress / 10)) + '░'.repeat(10 - Math.floor(prog.progress / 10));
console.log(chalk.gray(` ${time} ${chalk.cyan(prog.agent)} [${progressBar}] ${prog.progress}%`));
if (prog.description) {
console.log(chalk.gray(` ${prog.description}`));
}
});
}
}
async function generateAnalytics(period = 'week') {
const days = { day: 1, week: 7, month: 30 }[period] || 7;
const history = await getProjectHistory('all', null, days);
const analytics = {
period,
summary: {
totalMessages: history.messages.length,
totalTasks: history.tasks.length,
completedTasks: history.tasks.filter(t => t.action === 'complete').length,
blockedTasks: history.tasks.filter(t => t.action === 'block').length,
activeAgents: new Set([
...history.messages.map(m => m.from),
...history.messages.map(m => m.to),
...history.tasks.map(t => t.agent)
].filter(Boolean)).size
},
agentActivity: {},
taskCompletion: {},
hourlyActivity: new Array(24).fill(0),
productivity: {}
};
// Activity by agent
for (const msg of history.messages) {
analytics.agentActivity[msg.from] = (analytics.agentActivity[msg.from] || 0) + 1;
}
for (const task of history.tasks) {
if (!analytics.taskCompletion[task.agent]) {
analytics.taskCompletion[task.agent] = { started: 0, completed: 0, blocked: 0 };
}
analytics.taskCompletion[task.agent][task.action === 'start' ? 'started' : task.action === 'complete' ? 'completed' : 'blocked']++;
}
// Time-based activity
for (const item of [...history.messages, ...history.tasks]) {
const hour = new Date(item.timestamp).getHours();
analytics.hourlyActivity[hour]++;
}
// Productivity calculation
for (const agent in analytics.taskCompletion) {
const tc = analytics.taskCompletion[agent];
analytics.productivity[agent] = {
completionRate: tc.started > 0 ? Math.round((tc.completed / tc.started) * 100) : 0,
blockRate: tc.started > 0 ? Math.round((tc.blocked / tc.started) * 100) : 0
};
}
return analytics;
}
function displayAnalytics(analytics) {
console.log(chalk.blue(`📊 Project Analytics (${analytics.period})\n`));
// Summary
console.log(chalk.yellow('📈 Summary:'));
console.log(chalk.gray(` Messages: ${analytics.summary.totalMessages}`));
console.log(chalk.gray(` Tasks: ${analytics.summary.totalTasks} (${analytics.summary.completedTasks} completed, ${analytics.summary.blockedTasks} blocked)`));
console.log(chalk.gray(` Active Agents: ${analytics.summary.activeAgents}`));
console.log();
// Activity by agent
console.log(chalk.yellow('👥 Agent Activity:'));
Object.entries(analytics.agentActivity)
.sort(([,a], [,b]) => b - a)
.forEach(([agent, count]) => {
console.log(chalk.gray(` ${chalk.cyan(agent)}: ${count} messages`));
});
console.log();
// Task completion rate
console.log(chalk.yellow('✅ Task Completion:'));
Object.entries(analytics.productivity).forEach(([agent, stats]) => {
const completionBar = '█'.repeat(Math.floor(stats.completionRate / 10)) + '░'.repeat(10 - Math.floor(stats.completionRate / 10));
console.log(chalk.gray(` ${chalk.cyan(agent)}: [${completionBar}] ${stats.completionRate}% completion, ${stats.blockRate}% blocked`));
});
console.log();
// Most active time of day
const peakHour = analytics.hourlyActivity.indexOf(Math.max(...analytics.hourlyActivity));
console.log(chalk.yellow(`⏰ Peak Activity: ${peakHour}:00 (${analytics.hourlyActivity[peakHour]} events)`));
}
// Hook agent communication (enhanced for better message flow)
function hookAgentCommunication() {
// Create communication channels and status tracking
const d0Dir = path.join(process.cwd(), '.d0');
const commDir = path.join(d0Dir, 'tmp', 'communication');
if (!fs.existsSync(commDir)) {
fs.mkdirSync(commDir, { recursive: true });
}
// Create communication guidelines file for agents
const guidelinesFile = path.join(commDir, 'communication_guidelines.md');
const guidelines = `# Agent Communication Guidelines
## Message Flow
1. PRESIDENT → boss (via \`d0 tell boss "message"\`)
2. boss → workers (via \`d0 tell worker1 "message"\`)
3. workers → boss (progress reports)
4. boss → PRESIDENT (status updates)
## Important Notes for Agents
- Always check your inbox file: \`.d0/tmp/inbox/[your-role].txt\`
- Acknowledge messages by creating completion files
- Report progress every 30 minutes
- Escalate blockers immediately
## Notification System
- Notification files indicate new messages: \`.d0/tmp/inbox/[role]_notification.txt\`
- Message status tracking: \`.d0/tmp/message_status.json\`
Generated: ${new Date().toISOString()}
`;
fs.writeFileSync(guidelinesFile, guidelines);
// Set up periodic communication health check
const healthCheckFile = path.join(commDir, 'health_check.sh');
const healthCheck = `#!/bin/bash
# Communication Health Check
echo "🔄 Checking agent communication health..."
INBOX_DIR=".d0/tmp/inbox"
if [ -d "$INBOX_DIR" ]; then
echo "📬 Inbox status:"
for role in president boss worker1 worker2 worker3; do
if [ -f "$INBOX_DIR/$role.txt" ]; then
count=$(wc -l < "$INBOX_DIR/$role.txt")
if [ -f "$INBOX_DIR/$role_notification.txt" ]; then
echo " • $role: $count messages (🔔 unread)"
else
echo " • $role: $count messages"
fi
fi
done
else
echo "⚠️ No inbox directory found"
fi
echo "📊 Communication status: \$(date)"
`;
fs.writeFileSync(healthCheckFile, healthCheck);
fs.chmodSync(healthCheckFile, '755');
}
// Instruction template generation function
function generateInstructionTemplate(role, roleName, emoji, description) {
const currentYear = new Date().getFullYear();
return `# ${emoji} ${roleName} Instructions
## Your Role
As ${description}, develop high-quality deliverables quickly and contribute to team success.
## Immediate Actions
1. **Task Understanding (within 5 minutes)**
- Confirm requirements, ask questions immediately for unclear points
- Understand success criteria numerically
- Confirm dependencies
2. **Implementation Plan Creation (within 10 minutes)**
- Break down task into subtasks
- Estimate effort for each subtask
- Include test plan
3. **Start Implementation**
- Follow coding conventions
- Record progress every 30 minutes
- Report blockers immediately
## Practical Task Management
### Task Breakdown Template
\`\`\`markdown
## Task: [${role} Implementation]
### Subtasks and Effort
- [ ] Requirements analysis and design (0.5h)
- [ ] Basic implementation (2h)
- [ ] Test creation (1h)
- [ ] Quality check (0.5h)
- [ ] Documentation creation (0.5h)
- [ ] Code review response (0.5h)
### Total: 5h
### With buffer: 6h
\`\`\`
### Progress Report Format
\`\`\`bash
# 30-minute progress recording
echo "[\$(date +%H:%M)] Task: [task name] - Progress: [X]% - Status: [smooth/problematic]" >> progress.log
# Standard progress report
d0 tell boss "【Progress Report】${roleName} \$(date +%H:%M)
Task: [task name]
Progress: [X]% completed
Completed items:
✅ [completed subtask]
Working on:
🔄 [currently working subtask]
Next action:
→ [next subtask to work on]
Scheduled completion time: [HH:MM]
Issues: [none/present (details)]"
\`\`\`
## Blocker Response Process
### Immediate Report When Blocker Occurs
\`\`\`bash
# Report within 5 minutes after blocker detection
d0 tell boss "【Blocker Report】${roleName} \$(date +%H:%M)
## Problem
[Specific error content or issue]
## Attempts Made
1. [Trial 1 and result]
2. [Trial 2 and result]
## Impact
- Task impact: [estimated delay time]
- Impact on other tasks: [yes/no]
## Proposals
- Option A: [alternative plan, effort, risk]
- Option B: [alternative plan, effort, risk]
Please make decision."
\`\`\`
## Completion Report Template
### Task Completion Report
\`\`\`bash
# Create completion marker
touch ./.d0/tmp/${role}_done.txt
# Send completion report
d0 tell boss "【Completion Report】${roleName} \$(date +%H:%M)
## Task: [${role} Implementation]
✅ Completed
## Deliverables
1. [deliverable 1 path]
2. [deliverable 2 path]
3. [test file path]
## Quality Indicators
- Test coverage: [X]%
- Performance: [indicator value]
- Quality standards: [compliance status]
## Technical Points
- [Implementation innovation 1]
- [Implementation innovation 2]
- [Future improvement proposals]
## Next Actions
- [Next required work]
- [Dependent tasks]
Effort: Planned [X]h → Actual [Y]h"
\`\`\`
## ${role} Specialized Skills
### Core Skills
- [Technology 1]: [Detailed description]
- [Technology 2]: [Detailed description]
- [Technology 3]: [Detailed description]
### Quality Standards
- [Quality indicator 1]: [Target value]
- [Quality indicator 2]: [Target value]
- [Quality indicator 3]: [Target value]
### Best Practices
1. **[Practice item 1]**
- [Specific method]
- [Checkpoint]
2. **[Practice item 2]**
- [Specific method]
- [Checkpoint]
## Practical Success Principles
### Communication
- 📢 Progress reports every 30 minutes
- 🚨 Report blockers within 5 minutes
- ✅ Detailed reports upon completion
- 🤝 Information sharing between teams
### Quality Management
- Test coverage 80%+
- Code review required
- Simultaneous documentation creation
- Performance indicator compliance
### Time Management
- 1.2x estimate for buffer
- Early blocker reporting
- Maximize parallel work
- Minimize waiting time
## Checklist
\`\`\`bash
# Task start
echo "□ Completely understood requirements"
echo "□ Created effort estimates"
echo "□ Environment setup completed"
echo "□ Reported start to boss"
# Task completion
echo "□ All functions verified working"
echo "□ All tests pass"
echo "□ Documentation creation completed"
echo "□ Completion report sent"
\`\`\`
## Continuous Improvement
### Retrospective Items
- Today's learnings: [Technical discoveries]
- Improvement points: [Improvement proposals for next time]
- Team contribution: [Support to other members]
- Efficiency: [Work efficiency improvement ideas]
---
*Generated by Claude Agents v1.0.0 - ${currentYear}*
`;
}
// Session management using Node.js processes instead of tmux
function checkClaudeCLI() {
try {
const platform = os.platform();
if (platform === 'win32') {
// Try WSL first, then native Windows
try {
execSync('wsl claude --version', { stdio: 'ignore' });
return true;
} catch {
try {
execSync('claude --version', { stdio: 'ignore' });
return true;
} catch {
return false;
}
}
} else {
execSync('which claude', { stdio: 'ignore' });
return true;
}
} catch {
return false;
}
}
// Session management using Node.js child processes (cross-platform)
const activeSessions = new Map();
function createAgentSessions(numWorkers = 3) {
try {
// Stop existing sessions
stopAllSessions();
console.log(chalk.green('✅ Node.js agent sessions created!'));
console.log(chalk.yellow('💡 Available sessions:'));
console.log(chalk.gray(' • president - Project manager and overall supervisor'));
console.log(chalk.gray(' • boss - Team leader and tech lead'));
for (let i = 1; i <= numWorkers; i++) {
const workerSpec = getWorkerSpecialization(i);
console.log(chalk.gray(` • worker${i} - ${workerSpec.title}`));
}
console.log(chalk.yellow('\n💡 Next steps:'));
console.log(chalk.blue(' d0 hi president') + chalk.gray(' - Connect to project manager'));
console.log(chalk.blue(' d0 tell "Create a todo app"') + chalk.gray(' - Start your project'));
// Save session info to .d0/tmp
const sessionInfo = {
sessions: ['president', 'boss'].concat(Array.from({length: numWorkers}, (_, i) => `worker${i + 1}`)),
created: new Date().toISOString(),
numWorkers
};
const tmpDir = path.join(process.cwd(), '.d0', 'tmp');
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, { recursive: true });
}
fs.writeFileSync(path.join(tmpDir, 'sessions.json'), JSON.stringify(sessionInfo, null, 2));
return true;
} catch (error) {
console.error('Failed to create agent sessions:', error.message);
return false;
}
}
function stopAllSessions() {
activeSessions.forEach((session, name) => {
try {
session.process.kill('SIGTERM');
} catch (error) {
// Ignore if process is already dead
}
});
activeSessions.clear();
// Clean up session file
const sessionFile = path.join(process.cwd(), '.d0', 'tmp', 'sessions.json');
if (fs.existsSync(sessionFile)) {
fs.unlinkSync(sessionFile);
}
}
function connectToSession(sessionName) {
// Check if session