UNPKG

oneie

Version:

šŸ¤ ONE Personal Collaborative Intelligence - Creates personalized AI workspace from your me.md profile. Simple: npx oneie → edit me.md → generate personalized agents, workflows & missions. From students to enterprises, ONE adapts to your context.

612 lines (500 loc) • 19 kB
#!/usr/bin/env node /** * Mission Creation and Management System * Core system for creating, managing, and executing missions with human-AI collaboration */ import fs from 'fs-extra'; import path from 'path'; import yaml from 'js-yaml'; import chalk from 'chalk'; import inquirer from 'inquirer'; export class MissionSystem { constructor(projectPath = process.cwd()) { this.projectPath = projectPath; this.oneDir = path.join(projectPath, '.one'); this.missionsDir = path.join(this.oneDir, 'missions'); this.storiesDir = path.join(this.oneDir, 'stories'); this.tasksDir = path.join(this.oneDir, 'tasks'); } async createMission(objective, options = {}) { console.log(chalk.blue('\nšŸŽÆ Creating new mission...')); // Step 1: Analyze project architecture const architecture = await this.analyzeArchitecture(); // Step 2: Generate mission template const missionTemplate = await this.generateMissionTemplate(objective, architecture); // Step 3: Human-AI collaboration on mission design const mission = await this.collaborativelyDesignMission(missionTemplate, options); // Step 4: Create mission file and directory structure await this.initializeMission(mission); // Step 5: Generate initial stories await this.generateInitialStories(mission); console.log(chalk.green(`\nāœ… Mission "${mission.name}" created successfully!`)); console.log(chalk.cyan(`šŸ“ Mission directory: .one/missions/${mission.id}/`)); return mission; } async analyzeArchitecture() { console.log(chalk.gray('šŸ” Analyzing project architecture...')); const architecture = { techStack: await this.detectTechStack(), projectStructure: await this.analyzeProjectStructure(), existingMissions: await this.getExistingMissions(), integrationPoints: await this.findIntegrationPoints() }; console.log(chalk.green('āœ… Architecture analysis complete')); return architecture; } async detectTechStack() { const techStack = { languages: [], frameworks: [], databases: [], cloud: [], tools: [] }; const detectors = [ { file: 'package.json', handler: this.detectJavaScriptStack }, { file: 'requirements.txt', handler: this.detectPythonStack }, { file: 'pom.xml', handler: this.detectJavaStack }, { file: 'go.mod', handler: this.detectGoStack }, { file: 'Cargo.toml', handler: this.detectRustStack }, { file: 'composer.json', handler: this.detectPHPStack } ]; for (const detector of detectors) { const filePath = path.join(this.projectPath, detector.file); if (await fs.pathExists(filePath)) { const detected = await detector.handler.call(this, filePath); this.mergeTechStack(techStack, detected); } } return techStack; } async detectJavaScriptStack(packagePath) { const packageJson = await fs.readJson(packagePath); const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; const techStack = { languages: ['JavaScript'], frameworks: [], databases: [], tools: [] }; // Detect frameworks if (deps.react) techStack.frameworks.push('React'); if (deps.vue) techStack.frameworks.push('Vue'); if (deps.angular) techStack.frameworks.push('Angular'); if (deps.express) techStack.frameworks.push('Express'); if (deps.next) techStack.frameworks.push('Next.js'); if (deps.nuxt) techStack.frameworks.push('Nuxt.js'); // Detect databases if (deps.mongodb || deps.mongoose) techStack.databases.push('MongoDB'); if (deps.pg || deps['node-postgres']) techStack.databases.push('PostgreSQL'); if (deps.mysql || deps.mysql2) techStack.databases.push('MySQL'); if (deps.sqlite3) techStack.databases.push('SQLite'); // Detect tools if (deps.typescript) { techStack.languages.push('TypeScript'); techStack.tools.push('TypeScript'); } if (deps.webpack) techStack.tools.push('Webpack'); if (deps.vite) techStack.tools.push('Vite'); if (deps.jest) techStack.tools.push('Jest'); return techStack; } async detectPythonStack(requirementsPath) { const requirements = await fs.readFile(requirementsPath, 'utf8'); const techStack = { languages: ['Python'], frameworks: [], databases: [], tools: [] }; // Detect frameworks if (requirements.includes('django')) techStack.frameworks.push('Django'); if (requirements.includes('flask')) techStack.frameworks.push('Flask'); if (requirements.includes('fastapi')) techStack.frameworks.push('FastAPI'); if (requirements.includes('streamlit')) techStack.frameworks.push('Streamlit'); // Detect databases if (requirements.includes('psycopg2') || requirements.includes('postgresql')) techStack.databases.push('PostgreSQL'); if (requirements.includes('pymongo')) techStack.databases.push('MongoDB'); if (requirements.includes('sqlite')) techStack.databases.push('SQLite'); // Detect ML/AI tools if (requirements.includes('tensorflow')) techStack.tools.push('TensorFlow'); if (requirements.includes('pytorch')) techStack.tools.push('PyTorch'); if (requirements.includes('pandas')) techStack.tools.push('Pandas'); if (requirements.includes('numpy')) techStack.tools.push('NumPy'); return techStack; } mergeTechStack(target, source) { for (const [key, values] of Object.entries(source)) { if (Array.isArray(values)) { target[key] = [...new Set([...target[key], ...values])]; } } } async analyzeProjectStructure() { const structure = { type: 'unknown', patterns: [], complexity: 'medium', hasTests: false, hasDocker: false, hasCI: false }; // Detect project type const files = await fs.readdir(this.projectPath); if (files.includes('src') && files.includes('public')) { structure.type = 'frontend'; structure.patterns.push('SPA'); } else if (files.includes('server.js') || files.includes('app.js')) { structure.type = 'backend'; structure.patterns.push('API'); } else if (files.includes('src') && files.includes('package.json')) { structure.type = 'fullstack'; structure.patterns.push('monorepo'); } // Detect additional patterns if (files.includes('docker-compose.yml')) { structure.hasDocker = true; structure.patterns.push('containerized'); } if (files.includes('.github') || files.includes('.gitlab-ci.yml')) { structure.hasCI = true; structure.patterns.push('ci_cd'); } // Check for test directories if (files.some(f => f.includes('test') || f.includes('spec'))) { structure.hasTests = true; } return structure; } async generateMissionTemplate(objective, architecture) { console.log(chalk.gray('🧠 Generating mission template...')); const template = { name: this.generateMissionName(objective), id: this.generateMissionId(objective), objective: objective, architecture: architecture, suggestedAgents: this.suggestAgents(architecture), suggestedStories: this.suggestStories(objective, architecture), estimatedDuration: this.estimateDuration(objective, architecture), complexity: this.assessComplexity(objective, architecture) }; return template; } generateMissionName(objective) { // Convert objective to mission name return objective .toLowerCase() .replace(/[^a-z0-9\s]/g, '') .replace(/\s+/g, '-') .substring(0, 50); } generateMissionId(objective) { const timestamp = Date.now(); const hash = this.hashString(objective).substring(0, 8); return `mission-${hash}-${timestamp}`; } hashString(str) { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32-bit integer } return Math.abs(hash).toString(16); } suggestAgents(architecture) { const agents = []; // Base agents for all missions agents.push('Mission Commander', 'Task Master'); // Add agents based on tech stack if (architecture.techStack.frameworks.includes('React')) { agents.push('React Specialist', 'Frontend Developer'); } if (architecture.techStack.frameworks.includes('Express')) { agents.push('Backend Developer', 'API Designer'); } if (architecture.techStack.languages.includes('Python')) { agents.push('Python Developer', 'Data Analyst'); } if (architecture.techStack.databases.length > 0) { agents.push('Database Specialist'); } if (architecture.projectStructure.hasDocker) { agents.push('DevOps Engineer'); } if (architecture.projectStructure.hasTests) { agents.push('Quality Assurance Engineer'); } return agents; } suggestStories(objective, architecture) { const stories = []; // Generate stories based on objective keywords const objectiveLower = objective.toLowerCase(); if (objectiveLower.includes('api') || objectiveLower.includes('backend')) { stories.push('api-development', 'database-integration', 'authentication'); } if (objectiveLower.includes('ui') || objectiveLower.includes('frontend')) { stories.push('component-development', 'user-experience', 'responsive-design'); } if (objectiveLower.includes('test') || objectiveLower.includes('quality')) { stories.push('test-automation', 'quality-assurance', 'performance-testing'); } if (objectiveLower.includes('deploy') || objectiveLower.includes('production')) { stories.push('deployment-automation', 'monitoring-setup', 'security-hardening'); } // Default stories if none matched if (stories.length === 0) { stories.push('planning', 'development', 'testing', 'deployment'); } return stories; } estimateDuration(objective, architecture) { let baseDuration = 2; // weeks // Adjust based on complexity indicators if (architecture.projectStructure.complexity === 'high') baseDuration += 2; if (architecture.techStack.frameworks.length > 2) baseDuration += 1; if (architecture.projectStructure.hasDocker) baseDuration += 0.5; const complexityKeywords = ['complex', 'enterprise', 'large', 'scale', 'multiple']; const hasComplexityKeywords = complexityKeywords.some(keyword => objective.toLowerCase().includes(keyword) ); if (hasComplexityKeywords) baseDuration += 1; return `${Math.ceil(baseDuration)} weeks`; } assessComplexity(objective, architecture) { let score = 1; // base complexity score += architecture.techStack.languages.length * 0.5; score += architecture.techStack.frameworks.length * 0.3; score += architecture.techStack.databases.length * 0.2; if (architecture.projectStructure.hasDocker) score += 0.5; if (architecture.projectStructure.hasCI) score += 0.3; const complexityKeywords = ['integrate', 'migrate', 'refactor', 'optimize', 'scale']; const matchedKeywords = complexityKeywords.filter(keyword => objective.toLowerCase().includes(keyword) ).length; score += matchedKeywords * 0.4; if (score <= 2) return 'low'; if (score <= 3.5) return 'medium'; return 'high'; } async collaborativelyDesignMission(template, options) { console.log(chalk.blue('\nšŸ¤ Collaborative mission design...')); // Show AI analysis console.log(chalk.cyan('\nšŸ¤– AI Analysis:')); console.log(` Suggested name: ${template.name}`); console.log(` Estimated duration: ${template.estimatedDuration}`); console.log(` Complexity: ${template.complexity}`); console.log(` Suggested agents: ${template.suggestedAgents.join(', ')}`); if (options.interactive !== false) { // Get human input const answers = await inquirer.prompt([ { type: 'input', name: 'name', message: 'Mission name:', default: template.name }, { type: 'editor', name: 'description', message: 'Mission description:', default: `# ${template.objective}\n\n[Add detailed description of what this mission will accomplish]` }, { type: 'checkbox', name: 'agents', message: 'Select agents for this mission:', choices: template.suggestedAgents, default: template.suggestedAgents.slice(0, 4) // Select first 4 by default }, { type: 'input', name: 'duration', message: 'Expected duration:', default: template.estimatedDuration } ]); // Merge human input with AI suggestions template.name = answers.name; template.description = answers.description; template.agents = answers.agents; template.duration = answers.duration; } else { // Non-interactive mode - use AI suggestions template.agents = template.suggestedAgents.slice(0, 4); template.duration = template.estimatedDuration; template.description = `# ${template.objective}\n\nAI-generated mission to ${template.objective.toLowerCase()}.`; } console.log(chalk.green('āœ… Mission design complete')); return template; } async initializeMission(mission) { console.log(chalk.gray('šŸ“ Creating mission structure...')); // Ensure directories exist await fs.ensureDir(this.missionsDir); const missionDir = path.join(this.missionsDir, mission.id); await fs.ensureDir(missionDir); // Create mission.yaml file const missionData = { name: mission.name, id: mission.id, objective: mission.objective, description: mission.description, status: 'planning', created: new Date().toISOString(), agents: mission.agents, stories: mission.suggestedStories || [], duration: mission.duration, complexity: mission.complexity, architecture: mission.architecture }; await fs.writeFile( path.join(missionDir, 'mission.yaml'), yaml.dump(missionData, { indent: 2 }) ); // Create mission README const readmeContent = `# ${mission.name} ${mission.description} ## Objective ${mission.objective} ## Agents ${mission.agents.map(agent => `- ${agent}`).join('\n')} ## Stories ${mission.suggestedStories.map(story => `- [ ] ${story}`).join('\n')} ## Status - Created: ${new Date().toISOString()} - Status: Planning - Duration: ${mission.duration} - Complexity: ${mission.complexity} ## Architecture Context - Tech Stack: ${JSON.stringify(mission.architecture.techStack, null, 2)} - Project Type: ${mission.architecture.projectStructure.type} `; await fs.writeFile(path.join(missionDir, 'README.md'), readmeContent); // Create directories for stories and tasks await fs.ensureDir(path.join(missionDir, 'stories')); await fs.ensureDir(path.join(missionDir, 'tasks')); } async generateInitialStories(mission) { console.log(chalk.gray('šŸ“š Generating initial stories...')); for (const storyName of mission.suggestedStories) { await this.createStory(mission.id, storyName, { auto: true, agents: mission.agents }); } } async createStory(missionId, storyName, options = {}) { const storyId = `story-${this.hashString(storyName).substring(0, 8)}`; const missionDir = path.join(this.missionsDir, missionId); const storiesDir = path.join(missionDir, 'stories'); const storyData = { name: storyName, id: storyId, missionId: missionId, status: 'planning', created: new Date().toISOString(), agents: options.agents || [], tasks: [], description: options.auto ? `Auto-generated story for ${storyName} within mission ${missionId}` : options.description || '' }; await fs.writeFile( path.join(storiesDir, `${storyId}.yaml`), yaml.dump(storyData, { indent: 2 }) ); return storyData; } async listMissions() { if (!await fs.pathExists(this.missionsDir)) { return []; } const missionDirs = await fs.readdir(this.missionsDir); const missions = []; for (const dir of missionDirs) { const missionFile = path.join(this.missionsDir, dir, 'mission.yaml'); if (await fs.pathExists(missionFile)) { const missionData = yaml.load(await fs.readFile(missionFile, 'utf8')); missions.push(missionData); } } return missions; } async getMission(missionId) { const missionFile = path.join(this.missionsDir, missionId, 'mission.yaml'); if (await fs.pathExists(missionFile)) { return yaml.load(await fs.readFile(missionFile, 'utf8')); } return null; } async getExistingMissions() { return await this.listMissions(); } async findIntegrationPoints() { // Simple integration point detection const points = []; // Check for common integration patterns const commonPaths = [ 'src/', 'lib/', 'app/', 'components/', 'pages/', 'routes/', 'middleware/', 'services/' ]; for (const pathName of commonPaths) { const fullPath = path.join(this.projectPath, pathName); if (await fs.pathExists(fullPath)) { points.push({ path: pathName, type: this.inferIntegrationType(pathName), priority: this.calculateIntegrationPriority(pathName) }); } } return points.sort((a, b) => b.priority - a.priority); } inferIntegrationType(pathName) { const typeMap = { 'src/': 'source_code', 'lib/': 'library', 'app/': 'application', 'components/': 'ui_components', 'pages/': 'routing', 'routes/': 'api_routes', 'middleware/': 'middleware', 'services/': 'business_logic' }; return typeMap[pathName] || 'general'; } calculateIntegrationPriority(pathName) { const priorityMap = { 'src/': 9, 'app/': 8, 'lib/': 7, 'services/': 6, 'components/': 5, 'routes/': 4, 'pages/': 3, 'middleware/': 2 }; return priorityMap[pathName] || 1; } } // CLI interface functions export async function createMission(objective, options = {}) { const missionSystem = new MissionSystem(); return await missionSystem.createMission(objective, options); } export async function listMissions() { const missionSystem = new MissionSystem(); return await missionSystem.listMissions(); } export async function getMission(missionId) { const missionSystem = new MissionSystem(); return await missionSystem.getMission(missionId); }