UNPKG

@cabbages-pre/memory-pickle-mcp-pre

Version:

Simplified MCP server for AI agent project management - 8 essential tools for session memory and task tracking

123 lines (122 loc) 4.71 kB
import { generateId } from '../utils/idGenerator.js'; /** * Service responsible for project management operations */ export class ProjectService { /** * Creates a new project */ createProject(args) { const { name, description, status = 'planning' } = args; if (!name) { throw new Error('Project name is required'); } // Validate status if provided if (status && !['planning', 'in_progress', 'blocked', 'completed', 'archived'].includes(status)) { throw new Error(`Invalid project status: ${status}. Must be one of: planning, in_progress, blocked, completed, archived`); } return { id: generateId('proj'), name, description, created_date: new Date().toISOString(), status, completion_percentage: 0, tasks: [], milestones: [] }; } /** * Updates project completion percentage based on tasks */ updateProjectCompletion(project, tasks) { const projectTasks = tasks.filter(t => t.project_id === project.id); if (projectTasks.length === 0) { project.completion_percentage = 0; return; } const completedTasks = projectTasks.filter(t => t.completed).length; project.completion_percentage = Math.round((completedTasks / projectTasks.length) * 100); if (project.completion_percentage === 100) { project.status = 'completed'; } else if (project.completion_percentage > 0) { project.status = 'in_progress'; } } /** * Generates a comprehensive project summary */ generateProjectSummary(project, tasks) { const projectTasks = tasks.filter(t => t.project_id === project.id); const completed = projectTasks.filter(t => t.completed); const inProgress = projectTasks.filter(t => !t.completed && t.progress && t.progress > 0); const blocked = projectTasks.filter(t => t.blockers && t.blockers.length > 0); const critical = projectTasks.filter(t => t.priority === 'critical'); const recentCompletions = completed .filter(t => t.completed_date) .sort((a, b) => new Date(b.completed_date).getTime() - new Date(a.completed_date).getTime()) .slice(0, 5); const upcoming = projectTasks .filter(t => !t.completed) .sort((a, b) => { const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 }; return priorityOrder[a.priority] - priorityOrder[b.priority]; }) .slice(0, 5); return { project, total_tasks: projectTasks.length, completed_tasks: completed.length, in_progress_tasks: inProgress.length, blocked_tasks: blocked.length, recent_completions: recentCompletions, upcoming_tasks: upcoming, critical_items: critical, completion_percentage: project.completion_percentage }; } /** * Updates a project with new values */ updateProject(projects, projectId, updates) { const project = this.findProjectById(projects, projectId); if (!project) { throw new Error(`Project not found: ${projectId}`); } // Apply updates Object.assign(project, updates); return project; } /** * Finds a project by ID */ findProjectById(projects, projectId) { return projects.find(p => p.id === projectId); } /** * Gets the completion percentage for a project */ getProjectCompletion(projects, projectId) { const project = this.findProjectById(projects, projectId); return project?.completion_percentage || 0; } /** * Formats all projects overview */ formatAllProjectsOverview(projects, tasks) { if (projects.length === 0) { return `📋 No projects found. Use \`create_project\` to start a new project.`; } let result = `# 📊 All Projects Overview\n\n`; projects.forEach(project => { const projectTasks = tasks.filter(t => t.project_id === project.id); const completedTasks = projectTasks.filter(t => t.completed).length; result += `## ${project.name}\n`; result += `**Status:** ${project.status} | **Completion:** ${project.completion_percentage}%\n`; result += `**Tasks:** ${completedTasks}/${projectTasks.length} completed\n`; result += `**ID:** ${project.id}\n\n`; }); return result; } }