UNPKG

@systemprompt/mcp-taskchecker

Version:

Model Context Protocol (MCP) server for intelligent task management, evaluation scoring, and session-based workflow tracking. Seamlessly integrates with AI assistants to provide structured task orchestration, real-time progress monitoring, and comprehensi

129 lines (128 loc) 4.38 kB
import { randomUUID } from 'node:crypto'; export class TaskService { static instance; taskLists = new Map(); cleanupInterval; CLEANUP_INTERVAL = 60 * 60 * 1000; // 1 hour MAX_AGE = 24 * 60 * 60 * 1000; // 24 hours constructor() { // Start cleanup interval this.cleanupInterval = setInterval(() => { this.cleanupOldTaskLists(); }, this.CLEANUP_INTERVAL); } static getInstance() { if (!TaskService.instance) { TaskService.instance = new TaskService(); } return TaskService.instance; } createTaskList(sessionId, initialTasks) { const taskListId = randomUUID(); const now = new Date(); const tasks = initialTasks?.map(task => ({ id: randomUUID(), title: task.title, status: 'pending', acceptanceCriteria: task.acceptanceCriteria, createdAt: now, updatedAt: now, })) || []; const taskList = { id: taskListId, sessionId, tasks, createdAt: now, lastAccessed: now, }; this.taskLists.set(taskListId, taskList); return taskList; } getTaskList(taskListId) { const taskList = this.taskLists.get(taskListId); if (taskList) { // Update last accessed time taskList.lastAccessed = new Date(); this.taskLists.set(taskListId, taskList); } return taskList || null; } updateTask(taskListId, taskId, updates) { const taskList = this.getTaskList(taskListId); if (!taskList) return null; const taskIndex = taskList.tasks.findIndex(task => task.id === taskId); if (taskIndex === -1) return null; const task = taskList.tasks[taskIndex]; // Validate evaluation score if (updates.evaluation !== undefined && (updates.evaluation < 0 || updates.evaluation > 100)) { throw new Error('Evaluation must be between 0 and 100'); } // Update task properties const updatedTask = { ...task, ...(updates.title !== undefined && { title: updates.title }), ...(updates.status !== undefined && { status: updates.status }), ...(updates.acceptanceCriteria !== undefined && { acceptanceCriteria: updates.acceptanceCriteria }), ...(updates.evaluation !== undefined && { evaluation: updates.evaluation }), updatedAt: new Date(), }; taskList.tasks[taskIndex] = updatedTask; taskList.lastAccessed = new Date(); this.taskLists.set(taskListId, taskList); return updatedTask; } getTask(taskListId, taskId) { const taskList = this.getTaskList(taskListId); if (!taskList) return null; return taskList.tasks.find(task => task.id === taskId) || null; } getAllTasks(taskListId) { const taskList = this.getTaskList(taskListId); return taskList ? taskList.tasks : null; } deleteTaskList(taskListId) { return this.taskLists.delete(taskListId); } deleteTaskListBySession(sessionId) { let deletedCount = 0; for (const [id, taskList] of this.taskLists.entries()) { if (taskList.sessionId === sessionId) { this.taskLists.delete(id); deletedCount++; } } return deletedCount; } cleanupOldTaskLists() { const now = Date.now(); let cleanedCount = 0; for (const [id, taskList] of this.taskLists.entries()) { if (now - taskList.lastAccessed.getTime() > this.MAX_AGE) { this.taskLists.delete(id); cleanedCount++; } } if (cleanedCount > 0) { console.log(`Cleaned up ${cleanedCount} old task lists`); } } getStats() { let totalTasks = 0; for (const taskList of this.taskLists.values()) { totalTasks += taskList.tasks.length; } return { totalTaskLists: this.taskLists.size, totalTasks, }; } destroy() { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); } this.taskLists.clear(); } }