vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
210 lines (209 loc) • 7.91 kB
JavaScript
import { JobStatus } from './index.js';
import logger from '../../logger.js';
export class JobExecutionAdapter {
executionCoordinator;
jobToExecutionMap = new Map();
executionToJobMap = new Map();
constructor(executionCoordinator) {
this.executionCoordinator = executionCoordinator;
}
convertJobToScheduledTask(job) {
const { toolName, params } = job;
const atomicTask = {
id: job.id,
title: `${toolName} execution`,
description: params.description || `Executing ${toolName} tool`,
status: 'pending',
priority: params.priority || 'medium',
type: 'development',
functionalArea: 'backend',
estimatedHours: params.estimatedHours || 1,
actualHours: undefined,
epicId: params.epicId || 'default-epic',
projectId: params.projectId || 'default-project',
dependencies: [],
dependents: [],
filePaths: [],
acceptanceCriteria: params.acceptanceCriteria || [`${toolName} execution completed successfully`],
testingRequirements: {
unitTests: [],
integrationTests: [],
performanceTests: [],
coverageTarget: 0
},
performanceCriteria: {},
qualityCriteria: {
codeQuality: [],
documentation: [],
typeScript: false,
eslint: false
},
integrationCriteria: {
compatibility: [],
patterns: []
},
validationMethods: {
automated: [],
manual: []
},
createdAt: new Date(job.createdAt),
updatedAt: new Date(job.updatedAt),
createdBy: 'job-manager',
tags: params.tags || [toolName],
metadata: {
createdAt: new Date(job.createdAt),
updatedAt: new Date(job.updatedAt),
createdBy: 'job-manager',
tags: params.tags || [toolName]
}
};
const scheduledTask = {
task: atomicTask,
scheduledStart: new Date(),
scheduledEnd: new Date(Date.now() + (params.estimatedHours || 1) * 60 * 60 * 1000),
assignedResources: {
memoryMB: params.estimatedMemoryMB || 256,
cpuWeight: params.estimatedCPUWeight || 1.0,
agentId: params.agentId
},
batchId: 0,
prerequisiteTasks: [],
dependentTasks: [],
metadata: {
algorithm: 'priority_first',
priorityScore: 0,
resourceScore: 0,
deadlineScore: 0,
dependencyScore: 0,
durationScore: 0,
systemLoadScore: 0,
complexityScore: 0,
businessImpactScore: 0,
agentAvailabilityScore: 0,
totalScore: 0,
scheduledAt: new Date(),
lastOptimized: new Date()
}
};
return scheduledTask;
}
async executeJob(job) {
try {
const scheduledTask = this.convertJobToScheduledTask(job);
const execution = await this.executionCoordinator.executeTask(scheduledTask);
this.jobToExecutionMap.set(job.id, execution.metadata.executionId);
this.executionToJobMap.set(execution.metadata.executionId, job.id);
logger.info({
jobId: job.id,
executionId: execution.metadata.executionId,
toolName: job.toolName
}, 'Job execution started via ExecutionCoordinator');
return execution.metadata.executionId;
}
catch (error) {
logger.error({
jobId: job.id,
toolName: job.toolName,
error: error instanceof Error ? error.message : String(error)
}, 'Failed to execute job via ExecutionCoordinator');
throw error;
}
}
async cancelJobExecution(jobId) {
const executionId = this.jobToExecutionMap.get(jobId);
if (!executionId) {
logger.warn({ jobId }, 'No execution found for job');
return false;
}
try {
const cancelled = await this.executionCoordinator.cancelExecution(executionId);
if (cancelled) {
logger.info({ jobId, executionId }, 'Job execution cancelled');
this.jobToExecutionMap.delete(jobId);
this.executionToJobMap.delete(executionId);
}
return cancelled;
}
catch (error) {
logger.error({
jobId,
executionId,
error: error instanceof Error ? error.message : String(error)
}, 'Failed to cancel job execution');
return false;
}
}
async getJobExecutionStatus(jobId) {
const executionId = this.jobToExecutionMap.get(jobId);
if (!executionId) {
return null;
}
const statusInfo = await this.executionCoordinator.getTaskExecutionStatus(jobId);
return statusInfo ? statusInfo.status : null;
}
convertExecutionStatusToJobStatus(executionStatus) {
switch (executionStatus) {
case 'queued':
return JobStatus.PENDING;
case 'running':
return JobStatus.RUNNING;
case 'completed':
return JobStatus.COMPLETED;
case 'failed':
case 'cancelled':
case 'timeout':
return JobStatus.FAILED;
default:
return JobStatus.PENDING;
}
}
async getJobExecutionResult(jobId) {
const executionId = this.jobToExecutionMap.get(jobId);
if (!executionId) {
return null;
}
const metrics = this.executionCoordinator.getExecutionMetrics();
logger.debug({
jobId,
executionId,
totalExecuted: metrics.totalTasksExecuted,
running: metrics.runningTasks
}, 'Retrieved execution metrics for job');
return null;
}
registerJobLifecycleHooks(jobStatusUpdater) {
this.executionCoordinator.onExecutionStateChange((event) => {
const jobId = this.executionToJobMap.get(event.executionId);
if (jobId) {
const jobStatus = this.convertExecutionStatusToJobStatus(event.newStatus);
const message = `Execution ${event.newStatus}: ${event.metadata?.reason || ''}`;
jobStatusUpdater(jobId, jobStatus, message.trim());
if (event.newStatus === 'completed' || event.newStatus === 'failed' ||
event.newStatus === 'cancelled' || event.newStatus === 'timeout') {
this.jobToExecutionMap.delete(jobId);
this.executionToJobMap.delete(event.executionId);
}
}
});
}
getJobIdFromExecutionId(executionId) {
return this.executionToJobMap.get(executionId);
}
getExecutionIdFromJobId(jobId) {
return this.jobToExecutionMap.get(jobId);
}
cleanup() {
this.jobToExecutionMap.clear();
this.executionToJobMap.clear();
}
}
let adapterInstance = null;
export function getJobExecutionAdapter(executionCoordinator) {
if (!adapterInstance && executionCoordinator) {
adapterInstance = new JobExecutionAdapter(executionCoordinator);
}
if (!adapterInstance) {
throw new Error('JobExecutionAdapter not initialized. Provide ExecutionCoordinator on first call.');
}
return adapterInstance;
}