vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
271 lines (270 loc) • 9.82 kB
JavaScript
import { getProjectOperations } from '../core/operations/project-operations.js';
import logger from '../../../logger.js';
import path from 'path';
import fs from 'fs/promises';
export async function extractProjectFromContext(context, projectPath) {
const workingPath = projectPath || process.cwd();
try {
logger.debug({ workingPath, sessionId: context.sessionId }, 'Starting project context extraction');
if (context.currentProject) {
logger.debug({ currentProject: context.currentProject }, 'Found project in session context');
return {
projectId: context.currentProject,
projectName: context.currentProject,
source: 'session',
confidence: 0.95
};
}
const gitResult = await extractFromGitRemote(workingPath);
if (gitResult.confidence > 0.8) {
logger.debug({ gitResult }, 'Extracted project from git remote');
return gitResult;
}
const packageResult = await extractFromPackageJson(workingPath);
if (packageResult.confidence > 0.7) {
logger.debug({ packageResult }, 'Extracted project from package.json');
return packageResult;
}
const directoryResult = extractFromDirectoryName(workingPath);
logger.debug({ directoryResult }, 'Using directory name as project context');
return directoryResult;
}
catch (error) {
logger.warn({ error, workingPath }, 'Project context extraction failed, using fallback');
return {
projectId: 'default-project',
projectName: 'Default Project',
source: 'fallback',
confidence: 0.1
};
}
}
export async function extractEpicFromContext(context, projectId) {
try {
logger.debug({ projectId, sessionId: context.sessionId }, 'Starting epic context extraction');
if (context.currentTask) {
const epicFromTask = await extractEpicFromTask(context.currentTask);
if (epicFromTask.confidence > 0.8) {
logger.debug({ epicFromTask }, 'Found epic from current task');
return epicFromTask;
}
}
if (projectId) {
const projectEpic = await extractEpicFromProject(projectId);
if (projectEpic.confidence > 0.6) {
logger.debug({ projectEpic }, 'Found epic from project');
return projectEpic;
}
}
const generatedEpic = generateEpicFromProject(projectId || 'default-project');
logger.debug({ generatedEpic }, 'Generated epic from project');
return generatedEpic;
}
catch (error) {
logger.warn({ error, projectId }, 'Epic context extraction failed, using fallback');
if (projectId && projectId !== 'default-project') {
return generateEpicFromProject(projectId);
}
return {
epicId: 'default-epic',
epicName: 'Default Epic',
source: 'fallback',
confidence: 0.1
};
}
}
async function extractFromGitRemote(projectPath) {
try {
const { exec } = await import('child_process');
const { promisify } = await import('util');
const execAsync = promisify(exec);
const { stdout } = await execAsync('git remote get-url origin', { cwd: projectPath });
const remoteUrl = stdout.trim();
if (remoteUrl) {
let projectName = '';
const httpsMatch = remoteUrl.match(/https:\/\/[^/]+\/[^/]+\/([^/]+)(?:\.git)?$/);
if (httpsMatch) {
projectName = httpsMatch[1];
}
const sshMatch = remoteUrl.match(/git@[^:]+:([^/]+\/)?([^/]+)(?:\.git)?$/);
if (sshMatch) {
projectName = sshMatch[2];
}
if (projectName) {
const projectId = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
return {
projectId,
projectName,
source: 'git',
confidence: 0.85
};
}
}
}
catch (error) {
logger.debug({ error, projectPath }, 'Git remote extraction failed');
}
return {
projectId: 'unknown-git-project',
projectName: 'Unknown Git Project',
source: 'git',
confidence: 0.2
};
}
async function extractFromPackageJson(projectPath) {
try {
const packageJsonPath = path.join(projectPath, 'package.json');
const packageContent = await fs.readFile(packageJsonPath, 'utf-8');
const packageJson = JSON.parse(packageContent);
if (packageJson.name) {
const projectName = packageJson.name;
const projectId = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
return {
projectId,
projectName,
source: 'package',
confidence: 0.75
};
}
}
catch (error) {
logger.debug({ error, projectPath }, 'Package.json extraction failed');
}
return {
projectId: 'unknown-package-project',
projectName: 'Unknown Package Project',
source: 'package',
confidence: 0.2
};
}
function extractFromDirectoryName(projectPath) {
const directoryName = path.basename(projectPath);
const projectId = directoryName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
return {
projectId,
projectName: directoryName,
source: 'directory',
confidence: 0.6
};
}
async function extractEpicFromTask(taskId) {
try {
const { getTaskOperations } = await import('../core/operations/task-operations.js');
const taskOps = getTaskOperations();
const taskResult = await taskOps.getTask(taskId);
if (taskResult.success && taskResult.data?.epicId) {
return {
epicId: taskResult.data.epicId,
epicName: taskResult.data.epicId,
source: 'session',
confidence: 0.9
};
}
}
catch (error) {
logger.debug({ error, taskId }, 'Epic extraction from task failed');
}
return {
epicId: 'unknown-epic',
epicName: 'Unknown Epic',
source: 'session',
confidence: 0.1
};
}
async function extractEpicFromProject(projectId) {
try {
const projectOps = getProjectOperations();
const projectResult = await projectOps.getProject(projectId);
if (projectResult.success && projectResult.data) {
const epicIds = projectResult.data.epicIds;
if (epicIds && epicIds.length > 0) {
const firstEpicId = epicIds[0];
return {
epicId: firstEpicId,
epicName: firstEpicId,
source: 'project',
confidence: 0.7
};
}
}
}
catch (error) {
logger.debug({ error, projectId }, 'Epic extraction from project failed');
}
const epicId = `project-epic-1`;
return {
epicId,
epicName: epicId,
source: 'project',
confidence: 0.7
};
}
export async function extractTaskListContext(projectPath) {
const workingPath = projectPath || process.cwd();
try {
logger.debug({ workingPath }, 'Starting task list context extraction');
const { TaskListIntegrationService } = await import('../integrations/task-list-integration.js');
const taskListService = TaskListIntegrationService.getInstance();
const existingTaskList = await taskListService.detectExistingTaskList(workingPath);
if (existingTaskList && existingTaskList.isAccessible) {
logger.debug({ taskListFile: existingTaskList.fileName }, 'Found existing task list file');
const parseResult = await taskListService.parseTaskList(existingTaskList.filePath);
if (parseResult.success && parseResult.taskListData) {
const projectName = parseResult.taskListData.metadata.projectName;
const projectId = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
return {
projectId,
projectName,
source: 'directory',
confidence: 0.85
};
}
}
logger.debug({ workingPath }, 'No accessible task list found');
}
catch (error) {
logger.debug({ error, workingPath }, 'Task list context extraction failed');
}
return {
projectId: 'no-task-list-project',
projectName: 'No Task List Project',
source: 'fallback',
confidence: 0.1
};
}
function generateEpicFromProject(projectId) {
const epicId = `${projectId}-main-epic`;
const epicName = `${projectId} Main Epic`;
return {
epicId,
epicName,
source: 'default',
confidence: 0.5
};
}
export function sanitizeProjectId(projectId) {
if (!projectId)
return '';
let sanitized = projectId
.toLowerCase()
.replace(/[^a-z0-9-]/g, '-')
.replace(/--+/g, '-');
if (sanitized.match(/^-+$/) || sanitized === '') {
return '';
}
sanitized = sanitized.replace(/^-+|-+$/g, '');
return sanitized;
}
export function sanitizeEpicId(epicId) {
if (!epicId)
return '';
let sanitized = epicId
.toLowerCase()
.replace(/[^a-z0-9-]/g, '-')
.replace(/--+/g, '-');
if (sanitized.match(/^-+$/) || sanitized === '') {
return '';
}
sanitized = sanitized.replace(/^-+|-+$/g, '');
return sanitized;
}