Spaces:
Paused
Paused
| /** | |
| * βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| * β MOTOR CORTEX SERVICE β | |
| * βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| * β The system's "hands" - executes actions in the real world β | |
| * β Git operations, file management, deployments, shell commands β | |
| * β All actions require approval workflow for safety β | |
| * βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| */ | |
| import { exec } from 'child_process'; | |
| import { promisify } from 'util'; | |
| import * as fs from 'fs/promises'; | |
| import * as path from 'path'; | |
| import { neo4jAdapter } from '../adapters/Neo4jAdapter.js'; | |
| import { v4 as uuidv4 } from 'uuid'; | |
| const execAsync = promisify(exec); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Types | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export type ActionType = | |
| | 'GIT_COMMIT' | |
| | 'GIT_PUSH' | |
| | 'GIT_BRANCH' | |
| | 'GIT_MERGE' | |
| | 'FILE_CREATE' | |
| | 'FILE_MODIFY' | |
| | 'FILE_DELETE' | |
| | 'SHELL_COMMAND' | |
| | 'NPM_INSTALL' | |
| | 'NPM_RUN' | |
| | 'DEPLOY' | |
| | 'RESTART_SERVICE'; | |
| export type ActionStatus = 'PENDING' | 'APPROVED' | 'REJECTED' | 'EXECUTING' | 'COMPLETED' | 'FAILED'; | |
| export interface ActionRequest { | |
| id: string; | |
| type: ActionType; | |
| description: string; | |
| command?: string; | |
| targetPath?: string; | |
| content?: string; | |
| params?: Record<string, unknown>; | |
| requestedBy: string; | |
| requestedAt: string; | |
| status: ActionStatus; | |
| requiresApproval: boolean; | |
| approvedBy?: string; | |
| approvedAt?: string; | |
| executedAt?: string; | |
| result?: ActionResult; | |
| riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'; | |
| } | |
| export interface ActionResult { | |
| success: boolean; | |
| output?: string; | |
| error?: string; | |
| duration_ms: number; | |
| artifacts?: string[]; | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Motor Cortex Service | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class MotorCortexService { | |
| private static instance: MotorCortexService; | |
| private actionQueue: Map<string, ActionRequest> = new Map(); | |
| private actionHistory: ActionRequest[] = []; | |
| // Safety configuration | |
| private readonly AUTO_APPROVE_RISK_LEVELS: ActionRequest['riskLevel'][] = ['LOW']; | |
| private readonly BLOCKED_COMMANDS = [ | |
| /rm\s+-rf\s+\//, // rm -rf / | |
| /mkfs/, // format disk | |
| /dd\s+if=/, // disk destroyer | |
| /:(){ :|:& };:/, // fork bomb | |
| />\s*\/dev\/sd/, // write to disk device | |
| /shutdown/, // system shutdown | |
| /reboot/, // system reboot | |
| /init\s+0/, // halt system | |
| ]; | |
| private readonly PROJECT_ROOT = process.cwd(); | |
| private constructor() { | |
| this.loadHistoryFromNeo4j(); | |
| } | |
| public static getInstance(): MotorCortexService { | |
| if (!MotorCortexService.instance) { | |
| MotorCortexService.instance = new MotorCortexService(); | |
| } | |
| return MotorCortexService.instance; | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Action Request & Approval | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * Request an action to be executed | |
| */ | |
| public async requestAction(params: { | |
| type: ActionType; | |
| description: string; | |
| command?: string; | |
| targetPath?: string; | |
| content?: string; | |
| params?: Record<string, unknown>; | |
| requestedBy: string; | |
| }): Promise<ActionRequest> { | |
| const riskLevel = this.assessRisk(params); | |
| const action: ActionRequest = { | |
| id: `action-${uuidv4()}`, | |
| type: params.type, | |
| description: params.description, | |
| command: params.command, | |
| targetPath: params.targetPath, | |
| content: params.content, | |
| params: params.params, | |
| requestedBy: params.requestedBy, | |
| requestedAt: new Date().toISOString(), | |
| status: 'PENDING', | |
| requiresApproval: !this.AUTO_APPROVE_RISK_LEVELS.includes(riskLevel), | |
| riskLevel | |
| }; | |
| // Check for blocked commands | |
| if (params.command && this.isBlockedCommand(params.command)) { | |
| action.status = 'REJECTED'; | |
| action.result = { | |
| success: false, | |
| error: 'Command blocked for safety reasons', | |
| duration_ms: 0 | |
| }; | |
| console.error(`[MotorCortex] π« Blocked dangerous command: ${params.command}`); | |
| return action; | |
| } | |
| this.actionQueue.set(action.id, action); | |
| // Auto-approve low-risk actions | |
| if (!action.requiresApproval) { | |
| return await this.approveAndExecute(action.id, 'SYSTEM_AUTO'); | |
| } | |
| // Persist pending action | |
| await this.persistAction(action); | |
| console.error(`[MotorCortex] π Action queued (${action.riskLevel}): ${action.description}`); | |
| return action; | |
| } | |
| /** | |
| * Approve a pending action | |
| */ | |
| public async approveAction(actionId: string, approvedBy: string): Promise<ActionRequest | null> { | |
| const action = this.actionQueue.get(actionId); | |
| if (!action || action.status !== 'PENDING') { | |
| return null; | |
| } | |
| return await this.approveAndExecute(actionId, approvedBy); | |
| } | |
| /** | |
| * Reject a pending action | |
| */ | |
| public rejectAction(actionId: string, rejectedBy: string): ActionRequest | null { | |
| const action = this.actionQueue.get(actionId); | |
| if (!action || action.status !== 'PENDING') { | |
| return null; | |
| } | |
| action.status = 'REJECTED'; | |
| action.approvedBy = rejectedBy; | |
| action.approvedAt = new Date().toISOString(); | |
| this.actionHistory.push(action); | |
| this.actionQueue.delete(actionId); | |
| console.error(`[MotorCortex] β Action rejected: ${action.description}`); | |
| return action; | |
| } | |
| /** | |
| * Approve and execute action | |
| */ | |
| private async approveAndExecute(actionId: string, approvedBy: string): Promise<ActionRequest> { | |
| const action = this.actionQueue.get(actionId)!; | |
| action.status = 'APPROVED'; | |
| action.approvedBy = approvedBy; | |
| action.approvedAt = new Date().toISOString(); | |
| console.error(`[MotorCortex] β Action approved: ${action.description}`); | |
| return await this.executeAction(action); | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Action Execution | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * Execute an approved action | |
| */ | |
| private async executeAction(action: ActionRequest): Promise<ActionRequest> { | |
| action.status = 'EXECUTING'; | |
| action.executedAt = new Date().toISOString(); | |
| const startTime = Date.now(); | |
| try { | |
| let result: ActionResult; | |
| switch (action.type) { | |
| case 'GIT_COMMIT': | |
| result = await this.executeGitCommit(action); | |
| break; | |
| case 'GIT_PUSH': | |
| result = await this.executeGitPush(action); | |
| break; | |
| case 'GIT_BRANCH': | |
| result = await this.executeGitBranch(action); | |
| break; | |
| case 'FILE_CREATE': | |
| result = await this.executeFileCreate(action); | |
| break; | |
| case 'FILE_MODIFY': | |
| result = await this.executeFileModify(action); | |
| break; | |
| case 'FILE_DELETE': | |
| result = await this.executeFileDelete(action); | |
| break; | |
| case 'SHELL_COMMAND': | |
| result = await this.executeShellCommand(action); | |
| break; | |
| case 'NPM_INSTALL': | |
| result = await this.executeNpmInstall(action); | |
| break; | |
| case 'NPM_RUN': | |
| result = await this.executeNpmRun(action); | |
| break; | |
| default: | |
| result = { | |
| success: false, | |
| error: `Unsupported action type: ${action.type}`, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| action.result = result; | |
| action.status = result.success ? 'COMPLETED' : 'FAILED'; | |
| } catch (error: any) { | |
| action.status = 'FAILED'; | |
| action.result = { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| // Move to history | |
| this.actionHistory.push(action); | |
| this.actionQueue.delete(action.id); | |
| // Persist result | |
| await this.persistAction(action); | |
| const emoji = action.status === 'COMPLETED' ? 'β ' : 'β'; | |
| console.error(`[MotorCortex] ${emoji} Action ${action.status}: ${action.description}`); | |
| return action; | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Specific Action Handlers | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| private async executeGitCommit(action: ActionRequest): Promise<ActionResult> { | |
| const message = action.params?.message as string || action.description; | |
| const startTime = Date.now(); | |
| try { | |
| // Stage all changes | |
| await execAsync('git add -A', { cwd: this.PROJECT_ROOT }); | |
| // Commit | |
| const { stdout, stderr } = await execAsync( | |
| `git commit -m "${message.replace(/"/g, '\\"')}"`, | |
| { cwd: this.PROJECT_ROOT } | |
| ); | |
| return { | |
| success: true, | |
| output: stdout || stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeGitPush(action: ActionRequest): Promise<ActionResult> { | |
| const branch = action.params?.branch as string || 'main'; | |
| const startTime = Date.now(); | |
| try { | |
| const { stdout, stderr } = await execAsync( | |
| `git push origin ${branch}`, | |
| { cwd: this.PROJECT_ROOT } | |
| ); | |
| return { | |
| success: true, | |
| output: stdout || stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeGitBranch(action: ActionRequest): Promise<ActionResult> { | |
| const branchName = action.params?.branchName as string; | |
| const checkout = action.params?.checkout as boolean; | |
| const startTime = Date.now(); | |
| try { | |
| const command = checkout | |
| ? `git checkout -b ${branchName}` | |
| : `git branch ${branchName}`; | |
| const { stdout, stderr } = await execAsync(command, { cwd: this.PROJECT_ROOT }); | |
| return { | |
| success: true, | |
| output: stdout || stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeFileCreate(action: ActionRequest): Promise<ActionResult> { | |
| const startTime = Date.now(); | |
| const targetPath = action.targetPath!; | |
| const content = action.content || ''; | |
| try { | |
| // Ensure directory exists | |
| await fs.mkdir(path.dirname(targetPath), { recursive: true }); | |
| // Create file | |
| await fs.writeFile(targetPath, content, 'utf-8'); | |
| return { | |
| success: true, | |
| output: `Created: ${targetPath}`, | |
| duration_ms: Date.now() - startTime, | |
| artifacts: [targetPath] | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeFileModify(action: ActionRequest): Promise<ActionResult> { | |
| const startTime = Date.now(); | |
| const targetPath = action.targetPath!; | |
| const content = action.content!; | |
| try { | |
| await fs.writeFile(targetPath, content, 'utf-8'); | |
| return { | |
| success: true, | |
| output: `Modified: ${targetPath}`, | |
| duration_ms: Date.now() - startTime, | |
| artifacts: [targetPath] | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeFileDelete(action: ActionRequest): Promise<ActionResult> { | |
| const startTime = Date.now(); | |
| const targetPath = action.targetPath!; | |
| try { | |
| await fs.unlink(targetPath); | |
| return { | |
| success: true, | |
| output: `Deleted: ${targetPath}`, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeShellCommand(action: ActionRequest): Promise<ActionResult> { | |
| const startTime = Date.now(); | |
| const command = action.command!; | |
| try { | |
| const { stdout, stderr } = await execAsync(command, { | |
| cwd: this.PROJECT_ROOT, | |
| timeout: 60000 // 1 minute timeout | |
| }); | |
| return { | |
| success: true, | |
| output: stdout || stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| output: error.stdout || error.stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeNpmInstall(action: ActionRequest): Promise<ActionResult> { | |
| const startTime = Date.now(); | |
| const packageName = action.params?.package as string; | |
| try { | |
| const command = packageName | |
| ? `npm install ${packageName}` | |
| : 'npm install'; | |
| const { stdout, stderr } = await execAsync(command, { | |
| cwd: this.PROJECT_ROOT, | |
| timeout: 300000 // 5 minute timeout | |
| }); | |
| return { | |
| success: true, | |
| output: stdout || stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| private async executeNpmRun(action: ActionRequest): Promise<ActionResult> { | |
| const startTime = Date.now(); | |
| const script = action.params?.script as string; | |
| try { | |
| const { stdout, stderr } = await execAsync(`npm run ${script}`, { | |
| cwd: this.PROJECT_ROOT, | |
| timeout: 300000 // 5 minute timeout | |
| }); | |
| return { | |
| success: true, | |
| output: stdout || stderr, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } catch (error: any) { | |
| return { | |
| success: false, | |
| error: error.message, | |
| duration_ms: Date.now() - startTime | |
| }; | |
| } | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Risk Assessment | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| private assessRisk(params: { type: ActionType; command?: string; targetPath?: string }): ActionRequest['riskLevel'] { | |
| // File deletion is high risk | |
| if (params.type === 'FILE_DELETE') return 'HIGH'; | |
| // Git push is medium risk | |
| if (params.type === 'GIT_PUSH' || params.type === 'GIT_MERGE') return 'MEDIUM'; | |
| // Deployment is critical | |
| if (params.type === 'DEPLOY' || params.type === 'RESTART_SERVICE') return 'CRITICAL'; | |
| // Shell commands need careful assessment | |
| if (params.type === 'SHELL_COMMAND' && params.command) { | |
| if (/sudo|rm|chmod|chown/i.test(params.command)) return 'HIGH'; | |
| if (/curl|wget|npm|pip/i.test(params.command)) return 'MEDIUM'; | |
| } | |
| // File creation/modification outside project | |
| if (params.targetPath && !params.targetPath.startsWith(this.PROJECT_ROOT)) { | |
| return 'HIGH'; | |
| } | |
| return 'LOW'; | |
| } | |
| private isBlockedCommand(command: string): boolean { | |
| return this.BLOCKED_COMMANDS.some(pattern => pattern.test(command)); | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Query Functions | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| public getPendingActions(): ActionRequest[] { | |
| return Array.from(this.actionQueue.values()).filter(a => a.status === 'PENDING'); | |
| } | |
| public getActionHistory(limit: number = 50): ActionRequest[] { | |
| return this.actionHistory.slice(-limit); | |
| } | |
| public getAction(actionId: string): ActionRequest | undefined { | |
| return this.actionQueue.get(actionId) || this.actionHistory.find(a => a.id === actionId); | |
| } | |
| public getStatus(): { | |
| pendingActions: number; | |
| executingActions: number; | |
| completedToday: number; | |
| failedToday: number; | |
| } { | |
| const today = new Date().toISOString().split('T')[0]; | |
| const todayActions = this.actionHistory.filter(a => | |
| a.executedAt?.startsWith(today) | |
| ); | |
| return { | |
| pendingActions: this.getPendingActions().length, | |
| executingActions: Array.from(this.actionQueue.values()).filter(a => a.status === 'EXECUTING').length, | |
| completedToday: todayActions.filter(a => a.status === 'COMPLETED').length, | |
| failedToday: todayActions.filter(a => a.status === 'FAILED').length | |
| }; | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Persistence | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| private async persistAction(action: ActionRequest): Promise<void> { | |
| try { | |
| await neo4jAdapter.executeQuery(` | |
| MERGE (a:Action {id: $id}) | |
| SET a.type = $type, | |
| a.description = $description, | |
| a.status = $status, | |
| a.riskLevel = $riskLevel, | |
| a.requestedBy = $requestedBy, | |
| a.requestedAt = $requestedAt, | |
| a.approvedBy = $approvedBy, | |
| a.executedAt = $executedAt, | |
| a.success = $success | |
| `, { | |
| id: action.id, | |
| type: action.type, | |
| description: action.description, | |
| status: action.status, | |
| riskLevel: action.riskLevel, | |
| requestedBy: action.requestedBy, | |
| requestedAt: action.requestedAt, | |
| approvedBy: action.approvedBy || '', | |
| executedAt: action.executedAt || '', | |
| success: action.result?.success ?? null | |
| }); | |
| } catch (error) { | |
| console.warn('[MotorCortex] Failed to persist action:', error); | |
| } | |
| } | |
| private async loadHistoryFromNeo4j(): Promise<void> { | |
| try { | |
| const results = await neo4jAdapter.executeQuery(` | |
| MATCH (a:Action) | |
| WHERE a.executedAt IS NOT NULL | |
| RETURN a | |
| ORDER BY a.executedAt DESC | |
| LIMIT 100 | |
| `); | |
| // Load into history (simplified) | |
| console.error(`[MotorCortex] π Loaded ${results.length} actions from history`); | |
| } catch (error) { | |
| console.warn('[MotorCortex] Failed to load history:', error); | |
| } | |
| } | |
| } | |
| export const motorCortex = MotorCortexService.getInstance(); | |