UNPKG

@notbnull/mcp-cursor-taskmaster

Version:

A project-scoped MCP server requiring explicit --project-dir configuration for task management, memory retrieval, and agentic workflows

230 lines 8.62 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TaskStore = void 0; const path_1 = __importDefault(require("path")); const promises_1 = __importDefault(require("fs/promises")); const crypto_1 = __importDefault(require("crypto")); class TaskStore { dataDir; tasksPath; promptsPath; listsPath; workflowPath; constructor(projectDir) { // Use the provided project directory directly - it's validated upstream this.dataDir = path_1.default.join(path_1.default.resolve(projectDir), ".taskmaster"); this.tasksPath = path_1.default.join(this.dataDir, "tasks.json"); this.promptsPath = path_1.default.join(this.dataDir, "prompts.json"); this.listsPath = path_1.default.join(this.dataDir, "lists.json"); this.workflowPath = path_1.default.join(this.dataDir, "workflow.json"); } async initialize() { try { // Ensure .taskmaster directory exists console.error(`TaskStore: Creating directory ${this.dataDir}`); await promises_1.default.mkdir(this.dataDir, { recursive: true }); // Initialize JSON files if they don't exist await this.ensureFileExists(this.tasksPath, {}); await this.ensureFileExists(this.promptsPath, {}); await this.ensureFileExists(this.listsPath, {}); await this.ensureFileExists(this.workflowPath, { executionLog: [], }); console.error(`TaskStore: Successfully initialized in ${this.dataDir}`); } catch (error) { console.error(`TaskStore: Failed to initialize in ${this.dataDir}:`, error); throw new Error(`Failed to initialize TaskStore: ${error instanceof Error ? error.message : "Unknown error"}`); } } async ensureFileExists(filePath, defaultContent) { try { await promises_1.default.access(filePath); } catch { await promises_1.default.writeFile(filePath, JSON.stringify(defaultContent, null, 2)); } } async readJsonFile(filePath) { const content = await promises_1.default.readFile(filePath, "utf-8"); return JSON.parse(content); } async writeJsonFile(filePath, data) { await promises_1.default.writeFile(filePath, JSON.stringify(data, null, 2)); } // Task operations async createTask(taskData) { const tasks = await this.readJsonFile(this.tasksPath); const task = { id: crypto_1.default.randomUUID(), ...taskData, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), children: [], }; tasks[task.id] = task; // If this task has a parent, add it to parent's children if (task.parentId && tasks[task.parentId]) { const parent = tasks[task.parentId]; parent.children = parent.children || []; parent.children.push(task.id); parent.updatedAt = new Date().toISOString(); } await this.writeJsonFile(this.tasksPath, tasks); return task; } async getTask(id) { const tasks = await this.readJsonFile(this.tasksPath); return tasks[id] || null; } async getAllTasks() { const tasks = await this.readJsonFile(this.tasksPath); return Object.values(tasks); } async updateTask(id, updates) { const tasks = await this.readJsonFile(this.tasksPath); if (!tasks[id]) return null; tasks[id] = { ...tasks[id], ...updates, updatedAt: new Date().toISOString(), }; await this.writeJsonFile(this.tasksPath, tasks); return tasks[id]; } async deleteTask(id) { const tasks = await this.readJsonFile(this.tasksPath); if (!tasks[id]) return false; const task = tasks[id]; // Remove from parent's children if it has a parent if (task.parentId && tasks[task.parentId]) { tasks[task.parentId].children = tasks[task.parentId].children?.filter((childId) => childId !== id) || []; tasks[task.parentId].updatedAt = new Date().toISOString(); } // Delete all child tasks recursively if (task.children) { for (const childId of task.children) { await this.deleteTask(childId); } } delete tasks[id]; await this.writeJsonFile(this.tasksPath, tasks); return true; } // Prompt operations async createPrompt(promptData) { const prompts = await this.readJsonFile(this.promptsPath); const prompt = { id: crypto_1.default.randomUUID(), ...promptData, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; prompts[prompt.id] = prompt; await this.writeJsonFile(this.promptsPath, prompts); return prompt; } async getPrompt(id) { const prompts = await this.readJsonFile(this.promptsPath); return prompts[id] || null; } async getAllPrompts() { const prompts = await this.readJsonFile(this.promptsPath); return Object.values(prompts); } async updatePrompt(id, updates) { const prompts = await this.readJsonFile(this.promptsPath); if (!prompts[id]) return null; prompts[id] = { ...prompts[id], ...updates, updatedAt: new Date().toISOString(), }; await this.writeJsonFile(this.promptsPath, prompts); return prompts[id]; } // TaskList operations async createList(listData) { const lists = await this.readJsonFile(this.listsPath); const list = { id: crypto_1.default.randomUUID(), ...listData, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; lists[list.id] = list; await this.writeJsonFile(this.listsPath, lists); return list; } async getList(id) { const lists = await this.readJsonFile(this.listsPath); return lists[id] || null; } async getAllLists() { const lists = await this.readJsonFile(this.listsPath); return Object.values(lists); } // Workflow operations async getWorkflowState() { return await this.readJsonFile(this.workflowPath); } async updateWorkflowState(updates) { const currentState = await this.getWorkflowState(); const newState = { ...currentState, ...updates }; await this.writeJsonFile(this.workflowPath, newState); return newState; } async logWorkflowAction(action, status, taskId, details) { const state = await this.getWorkflowState(); state.executionLog.push({ timestamp: new Date().toISOString(), action, taskId, status, details, }); await this.writeJsonFile(this.workflowPath, state); } // Utility methods async getTaskHierarchy(rootTaskId) { const tasks = await this.readJsonFile(this.tasksPath); const allTasks = Object.values(tasks); if (rootTaskId) { return this.buildHierarchy(allTasks, rootTaskId); } // Return all root tasks (no parent) with their hierarchies const rootTasks = allTasks.filter((task) => !task.parentId); const result = []; for (const rootTask of rootTasks) { result.push(...this.buildHierarchy(allTasks, rootTask.id)); } return result; } buildHierarchy(allTasks, rootId) { const taskMap = new Map(allTasks.map((task) => [task.id, task])); const result = []; const addTaskWithChildren = (taskId, depth = 0) => { const task = taskMap.get(taskId); if (!task) return; result.push({ ...task, metadata: { ...task.metadata, depth } }); if (task.children) { for (const childId of task.children) { addTaskWithChildren(childId, depth + 1); } } }; addTaskWithChildren(rootId); return result; } } exports.TaskStore = TaskStore; //# sourceMappingURL=task-store.js.map