Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions UNICORN_FINAL/autonomous-orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ const DECISION_INTERVAL = parseInt(process.env.DECISION_INTERVAL || '45'
const HEALTH_INTERVAL = 15 * 1000;
const BACKEND_HEAL_CMD = process.env.BACKEND_HEAL_CMD || '';
const EDGE_HEALTH_URL = process.env.EDGE_HEALTH_URL || process.env.PUBLIC_APP_URL || '';
const GH_PULL_INTERVAL = parseInt(process.env.GH_PULL_INTERVAL || '600', 10) * 1000; // 10 min
const GH_BRANCH = process.env.GITHUB_DEFAULT_BRANCH || 'main';

let innovationEngine, revenueEngine, viralEngine, controlPlaneAgent, profitControlLoop;
let innovationEngine, revenueEngine, viralEngine, controlPlaneAgent, profitControlLoop, githubOps;

// ─── Load engines gracefully (modules export singleton instances) ────────────
try {
Expand Down Expand Up @@ -63,6 +65,13 @@ try {
console.warn('⚠️ [ORCHESTRATOR] Profit Control Loop unavailable:', e.message);
}

try {
githubOps = require(path.join(BASE, 'github-ops'));
console.log('🔧 [ORCHESTRATOR] GitHub Ops loaded');
} catch (e) {
console.warn('⚠️ [ORCHESTRATOR] GitHub Ops unavailable:', e.message);
}

// ─── Stats tracking ──────────────────────────────────────────────────────────
const stats = {
startTime: new Date(),
Expand All @@ -74,6 +83,7 @@ const stats = {
monitorCycles: 0,
decisionCycles: 0,
healthChecks: 0,
githubCycles: 0,
errors: 0,
};

Expand Down Expand Up @@ -305,7 +315,55 @@ async function runDecisionCycle() {
}
}

// ─── Health report ────────────────────────────────────────────────────────────
// ─── GitHub Operations cycle ──────────────────────────────────────────────────
async function runGithubCycle() {
stats.githubCycles++;
log('🔧', `GitHub Ops cycle #${stats.githubCycles}`);
if (!githubOps) {
log('⚠️', 'GitHub Ops not loaded — skipping');
return;
}
try {
const status = githubOps.getStatus();
if (!status.configured) {
log('⚠️', 'GitHub Ops not configured (GITHUB_TOKEN/GITHUB_REPOSITORY missing)');
return;
}

// 1. Pull latest from main branch
try {
const pullResult = await githubOps.pullLatest(GH_BRANCH);
log('⬇️', `git pull ${GH_BRANCH}`, { summary: pullResult.summary });
} catch (pullErr) {
log('⚠️', `git pull failed: ${pullErr.message}`);
}

// 2. Check if last CI workflow run failed → consider rollback
try {
const runs = await githubOps.getWorkflowRuns('deploy-hetzner.yml', 3);
const latestRun = runs[0];
if (latestRun && latestRun.conclusion === 'failure') {
log('🚨', 'Last deploy workflow FAILED — checking if rollback needed', { run: latestRun.id, sha: latestRun.sha });
const GH_AUTO_ROLLBACK = String(process.env.GH_AUTO_ROLLBACK || 'false').toLowerCase() === 'true';
if (GH_AUTO_ROLLBACK) {
log('⏪', `Auto-rollback enabled — reverting ${latestRun.sha}`);
await githubOps.rollback(latestRun.sha, GH_BRANCH);
}
} else if (latestRun) {
log('✅', `Latest workflow run: ${latestRun.status}/${latestRun.conclusion || 'pending'}`, { id: latestRun.id });
}
} catch (ciErr) {
log('⚠️', `CI status check failed: ${ciErr.message}`);
}

log('🔧', 'GitHub Ops cycle complete', githubOps.getStatus().ops);
} catch (e) {
stats.errors++;
log('❌', 'GitHub Ops cycle error:', e.message);
}
}


function printHealthReport() {
stats.healthChecks++;
const report = {
Expand All @@ -318,12 +376,14 @@ function printHealthReport() {
monitorCycles: stats.monitorCycles,
decisionCycles: stats.decisionCycles,
healthChecks: stats.healthChecks,
githubCycles: stats.githubCycles,
errors: stats.errors,
innovationEngine: innovationEngine ? 'ACTIVE' : 'MOCKED',
revenueEngine: revenueEngine ? 'ACTIVE' : 'MOCKED',
viralEngine: viralEngine ? 'ACTIVE' : 'MOCKED',
controlPlaneAgent: controlPlaneAgent ? 'ACTIVE' : 'MOCKED',
profitControlLoop: profitControlLoop ? 'ACTIVE' : 'MOCKED',
githubOps: githubOps ? 'ACTIVE' : 'UNAVAILABLE',
nextInnovation: `${Math.round(INNOVATION_INTERVAL / 1000)}s`,
nextRevenue: `${Math.round(REVENUE_INTERVAL / 1000)}s`,
nextViral: `${Math.round(VIRAL_INTERVAL / 1000)}s`,
Expand Down Expand Up @@ -354,6 +414,7 @@ process.on('uncaughtException', (err) => {
log('🦄', ` Platform check every ${PLATFORM_INTERVAL / 1000}s`);
log('🦄', ` Auto-Monitor every ${MONITOR_INTERVAL / 1000}s`);
log('🦄', ` Auto-Decision AI every ${DECISION_INTERVAL / 1000}s`);
log('🦄', ` GitHub pull/rollback every ${GH_PULL_INTERVAL / 1000}s`);
log('🦄', '══════════════════════════════════════════');

// Immediate first cycles
Expand All @@ -364,6 +425,7 @@ process.on('uncaughtException', (err) => {
await runPlatformCycle();
await runMonitorCycle();
await runDecisionCycle();
await runGithubCycle();
printHealthReport();

// Schedule recurring cycles
Expand All @@ -374,7 +436,8 @@ process.on('uncaughtException', (err) => {
setInterval(runPlatformCycle, PLATFORM_INTERVAL);
setInterval(runMonitorCycle, MONITOR_INTERVAL);
setInterval(runDecisionCycle, DECISION_INTERVAL);
setInterval(runGithubCycle, GH_PULL_INTERVAL);
setInterval(printHealthReport, HEALTH_INTERVAL);

log('✅', 'All 8 autonomous cycles scheduled and running 🚀');
log('✅', 'All 9 autonomous cycles scheduled and running 🚀');
})();
35 changes: 35 additions & 0 deletions UNICORN_FINAL/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ const profitLoop = require('./modules/profit-control-loop');
const centralOrchestrator = require('./modules/central-orchestrator');
const selfHealingEngine = require('./modules/self-healing-engine');
const autoInnovationLoop = require('./modules/auto-innovation-loop');
const githubOps = require('./modules/github-ops');

// ==================== DYNAMIC PRICING ENGINE ====================
const dynamicPricing = require('./modules/dynamic-pricing');
Expand Down Expand Up @@ -3286,6 +3287,40 @@ app.post('/api/innovation-loop/trigger', adminTokenMiddleware, async (req, res)
} catch (e) { res.status(500).json({ error: e.message }); }
});

// ==================== GITHUB OPS ROUTES ====================
app.get('/api/github-ops/status', (req, res) => {
res.json(githubOps.getStatus());
});
app.get('/api/github-ops/workflow-runs', adminTokenMiddleware, async (req, res) => {
try {
const workflowId = req.query.workflow || 'deploy-hetzner.yml';
const limit = Math.min(parseInt(req.query.limit || '10', 10), 50);
const runs = await githubOps.getWorkflowRuns(workflowId, limit);
res.json({ workflowId, runs });
} catch (e) { res.status(500).json({ error: e.message }); }
});
app.post('/api/github-ops/pull', adminTokenMiddleware, async (req, res) => {
try {
const branch = req.body.branch || process.env.GITHUB_DEFAULT_BRANCH || 'main';
const result = await githubOps.pullLatest(branch);
res.json({ success: true, branch, summary: result.summary });
} catch (e) { res.status(500).json({ error: e.message }); }
});
app.post('/api/github-ops/trigger-workflow', adminTokenMiddleware, async (req, res) => {
try {
const { workflowId = 'deploy-hetzner.yml', branch, inputs } = req.body;
const result = await githubOps.triggerWorkflow(workflowId, branch, inputs);
res.json(result);
} catch (e) { res.status(500).json({ error: e.message }); }
});
app.post('/api/github-ops/rollback', adminTokenMiddleware, async (req, res) => {
try {
const { commitSha, branch } = req.body;
const result = await githubOps.rollback(commitSha, branch);
res.json(result);
} catch (e) { res.status(500).json({ error: e.message }); }
});

// ==================== SELF CONSTRUCTION & TOTAL SYSTEM HEALER ROUTES ====================
app.get('/api/self-construction/status', adminTokenMiddleware, (req, res) => {
res.json({ module: 'SelfConstruction', status: 'active', hasRun: selfConstruction.hasRun });
Expand Down
Loading
Loading