Skip to main content
Glama
task-service.ts7.42 kB
import { promises as fs } from 'fs'; import path from 'path'; export interface Task { id: number; title: string; project?: string; due?: string; created_at: string; completed_at?: string; } export class TaskService { private tasksFile: string; constructor() { this.tasksFile = process.env.TASKS_FILE || './tasks.md'; } async createTask(title: string, project?: string, due?: string): Promise<Task> { try { console.log(`✅ Создание задачи: ${title}`); const tasks = await this.loadTasks(); const newTask: Task = { id: this.getNextId(tasks), title, project, due, created_at: new Date().toISOString(), }; tasks.push(newTask); await this.saveTasks(tasks); console.log(`✅ Задача создана: ${title} (ID: ${newTask.id})`); return newTask; } catch (error) { console.error('Ошибка создания задачи:', error); throw new Error(`Ошибка создания задачи: ${error}`); } } async listTasks(project?: string, status?: string): Promise<Task[]> { try { console.log(`📋 Список задач (проект: ${project || 'все'}, статус: ${status || 'все'})`); const tasks = await this.loadTasks(); let filteredTasks = tasks; // Фильтр по проекту if (project) { filteredTasks = filteredTasks.filter(task => task.project === project); } // Фильтр по статусу if (status === 'open') { filteredTasks = filteredTasks.filter(task => !task.completed_at); } else if (status === 'completed') { filteredTasks = filteredTasks.filter(task => task.completed_at); } console.log(`✅ Найдено задач: ${filteredTasks.length}`); return filteredTasks; } catch (error) { console.error('Ошибка получения списка задач:', error); throw new Error(`Ошибка получения списка задач: ${error}`); } } async completeTask(taskId: number): Promise<Task> { try { console.log(`✅ Завершение задачи: ${taskId}`); const tasks = await this.loadTasks(); const taskIndex = tasks.findIndex(task => task.id === taskId); if (taskIndex === -1) { throw new Error(`Задача с ID ${taskId} не найдена`); } tasks[taskIndex].completed_at = new Date().toISOString(); await this.saveTasks(tasks); console.log(`✅ Задача завершена: ${tasks[taskIndex].title}`); return tasks[taskIndex]; } catch (error) { console.error('Ошибка завершения задачи:', error); throw new Error(`Ошибка завершения задачи: ${error}`); } } async updateTask(taskId: number, updates: Partial<Task>): Promise<Task> { try { console.log(`✏️ Обновление задачи: ${taskId}`); const tasks = await this.loadTasks(); const taskIndex = tasks.findIndex(task => task.id === taskId); if (taskIndex === -1) { throw new Error(`Задача с ID ${taskId} не найдена`); } // Обновляем только разрешенные поля const allowedUpdates = ['title', 'project', 'due']; for (const [key, value] of Object.entries(updates)) { if (allowedUpdates.includes(key) && value !== undefined) { (tasks[taskIndex] as any)[key] = value; } } await this.saveTasks(tasks); console.log(`✅ Задача обновлена: ${tasks[taskIndex].title}`); return tasks[taskIndex]; } catch (error) { console.error('Ошибка обновления задачи:', error); throw new Error(`Ошибка обновления задачи: ${error}`); } } async deleteTask(taskId: number): Promise<void> { try { console.log(`🗑️ Удаление задачи: ${taskId}`); const tasks = await this.loadTasks(); const taskIndex = tasks.findIndex(task => task.id === taskId); if (taskIndex === -1) { throw new Error(`Задача с ID ${taskId} не найдена`); } tasks.splice(taskIndex, 1); await this.saveTasks(tasks); console.log(`✅ Задача удалена`); } catch (error) { console.error('Ошибка удаления задачи:', error); throw new Error(`Ошибка удаления задачи: ${error}`); } } private async loadTasks(): Promise<Task[]> { try { const content = await fs.readFile(this.tasksFile, 'utf-8'); return this.parseTasksFromMarkdown(content); } catch (error) { // Если файл не существует, возвращаем пустой массив if ((error as any).code === 'ENOENT') { return []; } throw error; } } private async saveTasks(tasks: Task[]): Promise<void> { const content = this.generateMarkdownFromTasks(tasks); await fs.writeFile(this.tasksFile, content, 'utf-8'); } private parseTasksFromMarkdown(content: string): Task[] { const tasks: Task[] = []; const lines = content.split('\n'); let currentTask: Partial<Task> = {}; for (const line of lines) { if (line.startsWith('## ')) { // Сохраняем предыдущую задачу if (currentTask.title) { tasks.push(currentTask as Task); } // Начинаем новую задачу currentTask = { title: line.substring(3).trim(), created_at: new Date().toISOString(), }; } else if (line.startsWith('- **Проект:**')) { currentTask.project = line.split('**Проект:**')[1].trim(); } else if (line.startsWith('- **Срок:**')) { currentTask.due = line.split('**Срок:**')[1].trim(); } else if (line.startsWith('- **Статус:** Завершено')) { currentTask.completed_at = new Date().toISOString(); } } // Добавляем последнюю задачу if (currentTask.title) { tasks.push(currentTask as Task); } // Назначаем ID tasks.forEach((task, index) => { task.id = index + 1; }); return tasks; } private generateMarkdownFromTasks(tasks: Task[]): string { if (tasks.length === 0) { return '# Задачи\n\nНет активных задач.'; } const lines = ['# Задачи\n']; for (const task of tasks) { lines.push(`## ${task.title}`); if (task.project) { lines.push(`- **Проект:** ${task.project}`); } if (task.due) { lines.push(`- **Срок:** ${task.due}`); } if (task.completed_at) { lines.push(`- **Статус:** Завершено`); } lines.push(''); } return lines.join('\n'); } private getNextId(tasks: Task[]): number { if (tasks.length === 0) return 1; return Math.max(...tasks.map(task => task.id)) + 1; } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Galiusbro/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server