Something went wrong. Try again.
An AI-powered SaaS development platform for building, customizing, and deploying modern applications directly from natural language at scal… zentro.arjunkrishna.dev
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
import { promises as fs } from 'fs';import { join, dirname } from 'path';import { spawn } from 'child_process';
import { ZentroAction } from './parser';import { broadcastToSSE } from '../helpers/sse';
const BASE_WORK_DIR = '/tmp/zentro';
// Executes a single action (file or shell)export async function executeAction( projectId: string, action: ZentroAction, baseWorkDir: string = BASE_WORK_DIR): Promise<{ success: boolean; output?: string; error?: string }> { // Project files are mounted directly at /tmp/zentro in the container // The manager mounts /tmp/zentro/projects/{projectId} from host to /tmp/zentro in container const projectPath = baseWorkDir; try { if (action.type === 'file') { if (!action.filePath) { throw new Error('File action requires filePath'); } return await executeFileAction(projectId, projectPath, action); } else if (action.type === 'shell') { return await executeShellAction(projectId, action, projectPath); } else { throw new Error(`Unknown action type: ${action.type}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, error: errorMessage }; }}
// Executes file creation/modification actionasync function executeFileAction( projectId: string, projectPath: string, action: ZentroAction): Promise<{ success: boolean; output?: string; error?: string }> { try { const filePath = join(projectPath, action.filePath!); const fileDir = dirname(filePath); // Ensure directory exists await fs.mkdir(fileDir, { recursive: true }); // Write file content await fs.writeFile(filePath, action.content, 'utf-8'); broadcastToSSE({ projectId, type: 'file_action', content: `Created/updated: ${action.filePath}` }); return { success: true, output: `File ${action.filePath} created/updated successfully` }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, error: `Failed to write file: ${errorMessage}` }; }}
// Executes shell command actionasync function executeShellAction( projectId: string, action: ZentroAction, projectPath: string): Promise<{ success: boolean; output?: string; error?: string }> { return new Promise((resolve) => { const command = action.content.trim(); // Parse command and arguments const parts = command.split(/\s+/); const cmd = parts[0]; const args = parts.slice(1); broadcastToSSE({ projectId, type: 'shell_action', content: `Executing: ${command}` }); const child = spawn(cmd, args, { cwd: projectPath, shell: true, stdio: ['ignore', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; child.stdout?.on('data', (data) => { const output = data.toString(); stdout += output; broadcastToSSE({ projectId, type: 'shell_output', content: output }); }); child.stderr?.on('data', (data) => { const output = data.toString(); stderr += output; broadcastToSSE({ projectId, type: 'shell_error', content: output }); }); child.on('close', (code) => { if (code === 0) { resolve({ success: true, output: stdout || 'Command executed successfully' }); } else { resolve({ success: false, error: stderr || `Command failed with exit code ${code}` }); } }); child.on('error', (error) => { resolve({ success: false, error: `Failed to execute command: ${error.message}` }); }); });}
// Executes all actions from an artifact in sequenceexport async function executeArtifact( projectId: string, actions: ZentroAction[], baseWorkDir: string = BASE_WORK_DIR): Promise<{ success: boolean; results: Array<{ action: ZentroAction; result: any }> }> { const results: Array<{ action: ZentroAction; result: any }> = []; for (const action of actions) { const result = await executeAction(projectId, action, baseWorkDir); results.push({ action, result }); if (!result.success && action.type === 'shell') { // Continue even if shell command fails, but log it console.warn(`Action failed: ${action.type}`, result.error); } else if (!result.success) { // File operations should not fail console.error(`Action failed: ${action.type}`, result.error); } } const allSuccess = results.every(r => r.result.success); return { success: allSuccess, results };}