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
JavaScript
/**
* 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);
}