UNPKG

@codemafia0000/d0

Version:

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

187 lines (152 loc) • 6.32 kB
const fs = require('fs'); const path = require('path'); const os = require('os'); const { execSync, spawn } = require('child_process'); const ora = require('ora'); const chalk = require('chalk'); const CONSTANTS = require('../constants'); const { setupShellCompletion } = require('./shell-completion'); const { updateGitignore } = require('../utils/git-utils'); const { getHistoryDir, logSessionEvent } = require('../history/session-history'); const { hookAgentCommunication } = require('../communication/agent-communication'); const { setupClaudeAutoApprove, setClaudeEnvironment } = require('../utils/claude-config'); function ensureConfigDir() { const homeDir = os.homedir(); const configDir = path.join(homeDir, '.d0'); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } return configDir; } function checkClaudeCLI() { try { execSync('claude --version', { stdio: 'ignore', timeout: 5000 }); return true; } catch { return false; } } 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 < CONSTANTS.MIN_WORKERS || numWorkers > CONSTANTS.MAX_WORKERS) { spinner.fail(`Number of workers must be between ${CONSTANTS.MIN_WORKERS} and ${CONSTANTS.MAX_WORKERS}`); process.exit(1); } // Check prerequisites (Claude CLI only, no tmux required) spinner.text = 'Checking prerequisites...'; if (!checkClaudeCLI()) { spinner.warn('Claude CLI is not found - you may need to install it later.'); console.log(chalk.yellow('šŸ’” Install Claude CLI when ready: https://docs.anthropic.com/en/docs/claude-code')); } else { spinner.text = 'Claude CLI found'; } // Create .d0 directory first const currentDir = CONSTANTS.PROJECT_ROOT; const d0Dir = CONSTANTS.D0_DIR; // 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); } // Skip Claude CLI authentication - user can authenticate manually when needed spinner.text = 'Skipping Claude CLI authentication (will be done when needed)...'; // Setup Claude CLI auto-approve mode spinner.text = 'Setting up Claude CLI auto-approve mode...'; setupClaudeAutoApprove(); setClaudeEnvironment(); // 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 = CONSTANTS.TEMPLATES_DIR; // Copy main files const filesToCopy = CONSTANTS.TEMPLATE_FILES; 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}`); } } // Create tmp subdirectory const setupTmpDir = CONSTANTS.TMP_DIR; if (!fs.existsSync(setupTmpDir)) { fs.mkdirSync(setupTmpDir); } // Create instructions subdirectory and copy instructions files const instructionsDir = CONSTANTS.INSTRUCTIONS_DIR; if (!fs.existsSync(instructionsDir)) { fs.mkdirSync(instructionsDir); } // Copy instructions files to .d0/instructions/ const templateInstructionsPath = path.join(CONSTANTS.TEMPLATES_DIR, 'instructions'); if (fs.existsSync(templateInstructionsPath)) { fs.cpSync(templateInstructionsPath, instructionsDir, { recursive: true, force: true }); } // Create config.json fs.writeFileSync(CONSTANTS.CONFIG_FILE, JSON.stringify({ created: new Date().toISOString(), version: CONSTANTS.VERSION, workers: numWorkers }, null, 2)); // 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: ') + chalk.yellow('⚠ Manual setup required (run: claude auth login)')); 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 isProjectSetup() { return fs.existsSync(CONSTANTS.D0_DIR) && fs.existsSync(CONSTANTS.CONFIG_FILE); } function getProjectConfig() { if (!isProjectSetup()) { throw new Error('Project not initialized. Run "d0 init" first.'); } const configData = JSON.parse(fs.readFileSync(CONSTANTS.CONFIG_FILE, 'utf8')); return configData; } module.exports = { setupProject, isProjectSetup, getProjectConfig, ensureConfigDir, checkClaudeCLI };