UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

219 lines (218 loc) 9.56 kB
import { readFile } from 'fs/promises'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import { existsSync } from 'fs'; import yaml from 'yaml'; import logger from '../../../logger.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); export class PromptService { static instance; promptCache = new Map(); promptsDir; constructor() { const possiblePaths = [ join(__dirname, '..', 'prompts'), join(__dirname, '..', '..', '..', '..', 'src', 'tools', 'vibe-task-manager', 'prompts'), join(process.cwd(), 'src', 'tools', 'vibe-task-manager', 'prompts'), join(process.cwd(), 'build', 'tools', 'vibe-task-manager', 'prompts') ]; this.promptsDir = possiblePaths.find(path => existsSync(path)) || possiblePaths[0]; logger.debug({ promptsDir: this.promptsDir, testedPaths: possiblePaths }, 'PromptService initialized with prompts directory'); } static getInstance() { if (!PromptService.instance) { PromptService.instance = new PromptService(); } return PromptService.instance; } async getPrompt(type) { try { const config = await this.loadPromptConfig(type); switch (type) { case 'decomposition': return config.system_prompt; case 'atomic_detection': return config.atomic_detection_prompt || config.system_prompt; case 'context_integration': return config.context_integration_prompt || config.system_prompt; case 'agent_system': return config.system_prompt; case 'coordination': return config.coordination_prompt || config.system_prompt; case 'escalation': return config.escalation_prompt || config.system_prompt; case 'intent_recognition': return config.system_prompt; case 'fallback': return config.fallback_prompt || config.system_prompt; default: throw new Error(`Unknown prompt type: ${type}`); } } catch (error) { logger.error({ err: error, type }, 'Failed to load prompt'); return this.getFallbackPrompt(type); } } async loadPromptConfig(type) { const cacheKey = type; if (this.promptCache.has(cacheKey)) { return this.promptCache.get(cacheKey); } try { const filename = this.getPromptFilename(type); const filePath = join(this.promptsDir, filename); logger.debug({ filePath, type, promptsDir: this.promptsDir }, 'Loading prompt configuration'); if (!existsSync(filePath)) { throw new Error(`Prompt file not found: ${filePath}`); } const fileContent = await readFile(filePath, 'utf-8'); if (!fileContent || fileContent.trim().length === 0) { throw new Error(`Prompt file is empty: ${filePath}`); } let config; try { config = yaml.parse(fileContent); } catch (yamlError) { throw new Error(`Failed to parse YAML in ${filePath}: ${yamlError instanceof Error ? yamlError.message : String(yamlError)}`); } this.validatePromptConfig(config, type); this.promptCache.set(cacheKey, config); logger.info({ type, version: config.version }, 'Prompt configuration loaded'); return config; } catch (error) { logger.error({ err: error, type, promptsDir: this.promptsDir, filename: this.getPromptFilename(type), fullPath: join(this.promptsDir, this.getPromptFilename(type)), cwd: process.cwd(), __dirname }, 'Failed to load prompt configuration'); throw error; } } getPromptFilename(type) { switch (type) { case 'decomposition': case 'atomic_detection': case 'context_integration': return 'decomposition-prompt.yaml'; case 'agent_system': case 'coordination': case 'escalation': return 'agent-system-prompt.yaml'; case 'intent_recognition': case 'fallback': return 'intent-recognition-prompt.yaml'; default: throw new Error(`No filename mapping for prompt type: ${type}`); } } validatePromptConfig(config, type) { if (!config.system_prompt) { throw new Error(`Missing system_prompt in configuration for type: ${type}`); } if (!config.version) { throw new Error(`Missing version in configuration for type: ${type}`); } if (!config.compatibility || !Array.isArray(config.compatibility)) { throw new Error(`Missing or invalid compatibility array for type: ${type}`); } if (type === 'atomic_detection' && !config.atomic_detection_prompt) { logger.warn({ type }, 'atomic_detection_prompt not found, using system_prompt'); } if (type === 'fallback' && !config.fallback_prompt) { logger.warn({ type }, 'fallback_prompt not found, using system_prompt'); } } getFallbackPrompt(type) { const fallbackPrompts = { decomposition: `You are an expert software development task decomposition specialist. Break down complex tasks into smaller, atomic sub-tasks that can be completed in 1-4 hours. Respond with valid JSON containing a subTasks array.`, atomic_detection: `You are an expert at determining if a software development task is atomic. Analyze the task and determine if it can be completed in 1-4 hours by a skilled developer. Respond with valid JSON containing isAtomic, confidence, reasoning, estimatedHours, complexityFactors, and recommendations.`, context_integration: `You are an expert at integrating codebase context into task analysis. Consider existing code patterns, architecture, and project characteristics when analyzing tasks.`, agent_system: `You are an autonomous AI development agent. Execute assigned tasks completely and correctly, following quality standards and coordination protocols. Report progress and communicate blockers clearly.`, coordination: `You are coordinating multiple AI agents working on related tasks. Ensure efficient collaboration, prevent conflicts, and optimize overall project progress.`, escalation: `You are handling escalations and complex issues that require specialized attention. Triage issues, gather relevant information, and facilitate resolution.`, intent_recognition: `You are an expert natural language processing system for task management. Analyze user input and identify specific task management intents with relevant parameters. Respond with valid JSON containing intent, confidence, parameters, and context.`, fallback: `I'm not sure what you'd like me to do. Could you please clarify your request? I can help with creating projects and tasks, checking status, running tasks, and managing agents.` }; return fallbackPrompts[type] || fallbackPrompts.fallback; } clearCache() { this.promptCache.clear(); logger.info('Prompt cache cleared'); } async reloadPrompt(type) { this.promptCache.delete(type); await this.loadPromptConfig(type); logger.info({ type }, 'Prompt reloaded'); } async getPromptMetadata(type) { const config = await this.loadPromptConfig(type); return { version: config.version, lastUpdated: config.last_updated, compatibility: config.compatibility }; } getAvailablePromptTypes() { return [ 'decomposition', 'atomic_detection', 'context_integration', 'agent_system', 'coordination', 'escalation', 'intent_recognition', 'fallback' ]; } async validateAllPrompts() { const valid = []; const invalid = []; for (const type of this.getAvailablePromptTypes()) { try { await this.getPrompt(type); valid.push(type); } catch (error) { invalid.push({ type, error: error instanceof Error ? error.message : 'Unknown error' }); } } return { valid, invalid }; } async getPromptWithVariables(type, variables) { let prompt = await this.getPrompt(type); for (const [key, value] of Object.entries(variables)) { const placeholder = `{{${key}}}`; prompt = prompt.replace(new RegExp(placeholder, 'g'), value); } return prompt; } } export function getPromptService() { return PromptService.getInstance(); } export async function getPrompt(type) { const service = getPromptService(); return service.getPrompt(type); }