self-replicating/packages/orchestrator/src/orchestrator.ts

309 lines
8.7 KiB
TypeScript

import { PrismaClient } from '@prisma/client';
import { WorkflowExecutor } from './workflows/workflow-executor';
import { DecisionEngine } from './decision-engine/rules';
import { AlertSystem } from './monitoring/alerts';
import { MetricsCollector } from './monitoring/metrics';
import { log } from './monitoring/logger';
import { config } from './utils/config';
import { businessInputSchema, validateBusinessIdea } from './utils/validators';
export class MetaOrchestrator {
private db: PrismaClient;
private workflowExecutor: WorkflowExecutor;
private decisionEngine: DecisionEngine;
private alerts: AlertSystem;
private metrics: MetricsCollector;
private isRunning: boolean = false;
constructor() {
this.db = new PrismaClient();
this.alerts = new AlertSystem(this.db);
this.metrics = new MetricsCollector(this.db);
this.workflowExecutor = new WorkflowExecutor(this.db, this.alerts);
this.decisionEngine = new DecisionEngine(this.db, this.alerts, this.metrics);
}
/**
* Initialize the orchestrator
*/
async initialize(): Promise<void> {
try {
log.info('Initializing MetaOrchestrator...');
// Test database connection
await this.db.$connect();
log.info('Database connected');
// Start background processes
this.startBackgroundProcesses();
this.isRunning = true;
log.info('MetaOrchestrator initialized successfully');
} catch (error) {
log.error('Failed to initialize MetaOrchestrator', error);
throw error;
}
}
/**
* Create a new business and start its lifecycle
*/
async createBusiness(input: {
name: string;
idea: string;
targetAudience?: string;
budget?: number;
}): Promise<{ id: string; name: string }> {
try {
// Validate input
const validated = businessInputSchema.parse(input);
// Validate business idea quality
const ideaValidation = validateBusinessIdea(validated.idea);
if (!ideaValidation.valid) {
throw new Error(`Invalid business idea: ${ideaValidation.issues.join(', ')}`);
}
// Create business record
const business = await this.db.business.create({
data: {
name: validated.name,
idea: validated.idea,
targetAudience: validated.targetAudience,
budget: validated.budget,
status: 'VALIDATING',
},
});
log.business.created(business.id, business.name, business.idea);
// Start lifecycle in background (non-blocking)
this.executeBusinessLifecycle(business.id).catch((error) => {
log.error('Business lifecycle execution failed', error, { businessId: business.id });
});
return {
id: business.id,
name: business.name,
};
} catch (error) {
log.error('Failed to create business', error);
throw error;
}
}
/**
* Execute the complete business lifecycle
*/
async executeBusinessLifecycle(businessId: string): Promise<void> {
try {
log.info('Starting business lifecycle', { businessId });
// PHASE 1: Market Validation (Sequential)
log.info('Phase 1: Market Validation', { businessId });
const validationResult = await this.workflowExecutor.run(businessId, 'MARKET_VALIDATION');
if (!validationResult.success || !validationResult.data?.viable) {
log.info('Business validation failed - shutting down', { businessId });
await this.shutdown(businessId, 'Market validation failed: not viable');
return;
}
// PHASE 2: MVP Development (Sequential)
log.info('Phase 2: MVP Development', { businessId });
const mvpResult = await this.workflowExecutor.run(businessId, 'MVP_DEVELOPMENT');
if (!mvpResult.success) {
log.error('MVP development failed', undefined, { businessId });
await this.shutdown(businessId, 'MVP development failed');
return;
}
// PHASE 3: Marketing Setup (Parallel)
log.info('Phase 3: Marketing Setup (parallel workflows)', { businessId });
const marketingResults = await this.workflowExecutor.runParallel(businessId, [
'LANDING_PAGE_SEO',
'PAID_ADS',
'CONTENT_MARKETING',
'EMAIL_AUTOMATION',
'ANALYTICS_SETUP',
]);
// Check if any critical marketing workflows failed
const failures = marketingResults.filter((r) => !r.success);
if (failures.length > 0) {
log.warn('Some marketing workflows failed', {
businessId,
failureCount: failures.length,
});
// Continue anyway - marketing workflows are not critical
}
// Update business status
await this.db.business.update({
where: { id: businessId },
data: { status: 'OPTIMIZING' },
});
// PHASE 4: Continuous Optimization Loop (Forever)
log.info('Phase 4: Starting continuous optimization', { businessId });
// This runs forever until business is shutdown/paused
await this.workflowExecutor.runForever(
businessId,
'OPTIMIZATION_LOOP',
config.app.optimizationIntervalMinutes
);
log.info('Business lifecycle completed', { businessId });
} catch (error) {
log.error('Business lifecycle error', error, { businessId });
await this.alerts.systemError(
`Business lifecycle failed for ${businessId}`,
error instanceof Error ? error.stack : undefined
);
}
}
/**
* Shutdown a business
*/
async shutdown(businessId: string, reason: string): Promise<void> {
log.info('Shutting down business', { businessId, reason });
// Pause all campaigns
await this.db.campaign.updateMany({
where: { businessId },
data: { active: false },
});
// Update business status
await this.db.business.update({
where: { id: businessId },
data: { status: 'SHUTDOWN' },
});
// Send alert
const business = await this.db.business.findUnique({
where: { id: businessId },
});
if (business) {
await this.alerts.sendAlert({
type: 'DECISION_EXECUTED',
severity: 'WARNING',
title: 'Business Shutdown',
message: `Business "${business.name}" has been shut down.\n\nReason: ${reason}`,
businessId,
metadata: { reason },
});
}
log.info('Business shutdown complete', { businessId });
}
/**
* Start background processes (decision evaluation)
*/
private startBackgroundProcesses(): void {
// Run decision evaluation periodically
setInterval(async () => {
try {
await this.evaluateAllBusinessDecisions();
} catch (error) {
log.error('Decision evaluation error', error);
}
}, config.app.decisionEvaluationIntervalMinutes * 60 * 1000);
log.info('Background processes started', {
decisionEvaluationInterval: config.app.decisionEvaluationIntervalMinutes,
});
}
/**
* Evaluate decisions for all active businesses
*/
private async evaluateAllBusinessDecisions(): Promise<void> {
const activeBusinesses = await this.db.business.findMany({
where: {
status: {
in: ['RUNNING_ADS', 'OPTIMIZING', 'SCALING'],
},
},
});
log.info(`Evaluating decisions for ${activeBusinesses.length} businesses`);
for (const business of activeBusinesses) {
try {
await this.decisionEngine.evaluateBusinessDaily(business.id);
} catch (error) {
log.error('Failed to evaluate business decisions', error, {
businessId: business.id,
});
}
}
}
/**
* Get business status
*/
async getBusinessStatus(businessId: string) {
const business = await this.db.business.findUnique({
where: { id: businessId },
include: {
workflows: {
orderBy: { createdAt: 'desc' },
take: 10,
},
campaigns: true,
decisions: {
orderBy: { createdAt: 'desc' },
take: 5,
},
},
});
if (!business) {
throw new Error('Business not found');
}
const metrics = await this.metrics.getBusinessMetrics(businessId);
const healthScore = await this.metrics.getHealthScore(businessId);
return {
...business,
metrics,
healthScore,
};
}
/**
* List all businesses
*/
async listBusinesses() {
return await this.db.business.findMany({
orderBy: { createdAt: 'desc' },
include: {
_count: {
select: {
workflows: true,
campaigns: true,
decisions: true,
},
},
},
});
}
/**
* Graceful shutdown
*/
async close(): Promise<void> {
log.info('Shutting down MetaOrchestrator...');
this.isRunning = false;
await this.db.$disconnect();
log.info('MetaOrchestrator shutdown complete');
}
}