Skip to main content
Glama

Eureka Labo Task Management MCP Server

by mazemaze
work-session.ts8.09 kB
/** * Work Session Tools * Manages development work sessions with git tracking */ import { getAPIClient } from '../api/client.js'; import { getConfig } from '../config.js'; import { getCurrentCommit, getCurrentBranch, captureWorkSessionChanges, isGitRepository, hasUncommittedChanges, } from '../tracking/git-tracker.js'; import { getBranchSessionManager } from '../managers/branch-session-manager.js'; // In-memory session storage (could be moved to file/db if needed) const activeSessions = new Map<string, WorkSession>(); interface WorkSession { taskId: string; startedAt: string; gitBaseline: string; branch: string; } /** * Start working on a task * Captures git baseline for later diff comparison */ export async function startWorkOnTask(taskId: string): Promise<{ success: boolean; message: string; session?: WorkSession; }> { const config = getConfig(); const workspacePath = config.workspacePath; // Check if workspace is a git repository const isRepo = await isGitRepository(workspacePath); if (!isRepo) { return { success: false, message: `Workspace ${workspacePath} is not a git repository. Please initialize git first.`, }; } // Note: We allow uncommitted changes at start. // The diff will be captured from baseline to working directory when completing. // Check if task already has an active session if (activeSessions.has(taskId)) { return { success: false, message: `Task ${taskId} already has an active work session.`, }; } try { const apiClient = getAPIClient(); const branchSessionManager = getBranchSessionManager(); // Get current git state const gitBaseline = await getCurrentCommit(workspacePath); const branch = await getCurrentBranch(workspacePath); // Update task status to in_progress await apiClient.updateTask(taskId, { status: 'in_progress', }); // Track task in branch session await branchSessionManager.trackTaskInBranch(taskId); // Create session const session: WorkSession = { taskId, startedAt: new Date().toISOString(), gitBaseline, branch, }; // Store active session activeSessions.set(taskId, session); return { success: true, message: `Started work session on task ${taskId}`, session, }; } catch (error: any) { return { success: false, message: `Failed to start work session: ${error.message}`, }; } } /** * Format changes into markdown description for task (in Japanese) */ function formatTaskDescription(summary: string, changes: any): string { const { statistics, changes: fileChanges, gitFinal, branch } = changes; let description = `## 🎯 実装概要\n\n${summary}\n\n`; // Statistics description += `## 📊 変更統計\n\n`; description += `- **変更ファイル数**: ${statistics.filesChanged}個\n`; description += `- **追加行数**: +${statistics.linesAdded}行\n`; description += `- **削除行数**: -${statistics.linesRemoved}行\n`; description += `- **ブランチ**: \`${branch}\`\n`; description += `- **コミット**: \`${gitFinal.substring(0, 7)}\`\n\n`; // File list description += `## 📁 変更ファイル一覧\n\n`; fileChanges.forEach((change: any) => { const icon = change.changeType === 'added' ? '➕' : change.changeType === 'deleted' ? '❌' : '✏️'; description += `${icon} \`${change.file}\` (+${change.linesAdded}/-${change.linesRemoved})\n`; }); description += `\n---\n\n`; description += `*詳細な差分はWork Sessionsタブで表示できます。*\n`; return description; } /** * Complete work on a task * Captures all changes and logs them to task metadata * Updates task description with formatted change summary */ export async function completeTaskWork( taskId: string, summary: string ): Promise<{ success: boolean; message: string; changes?: any; }> { const config = getConfig(); const workspacePath = config.workspacePath; // Check if task has an active session const session = activeSessions.get(taskId); if (!session) { return { success: false, message: `No active work session found for task ${taskId}. Use start_work_on_task first.`, }; } try { const apiClient = getAPIClient(); const branchSessionManager = getBranchSessionManager(); // Capture all changes since baseline (includes uncommitted changes) const changes = await captureWorkSessionChanges( workspacePath, session.gitBaseline ); // Check if any changes were captured if (changes.statistics.filesChanged === 0) { return { success: false, message: `⚠️ 変更が検出されませんでした。\n\nベースライン: ${session.gitBaseline}\n現在のHEAD: ${changes.gitFinal}\n\nファイルを編集してから再度実行してください。`, }; } // Create work session record // Flatten the diff structure to match API schema const workSession = { sessionId: `session_${Date.now()}`, startedAt: session.startedAt, completedAt: new Date().toISOString(), summary, gitBaseline: changes.gitBaseline, gitFinal: changes.gitFinal, branch: changes.branch, statistics: changes.statistics, changes: changes.changes.map((change) => ({ file: change.file, changeType: change.changeType, linesAdded: change.linesAdded, linesRemoved: change.linesRemoved, language: change.language, oldValue: change.diff.oldValue, // Flatten from diff.oldValue to oldValue newValue: change.diff.newValue, // Flatten from diff.newValue to newValue unifiedDiff: change.unifiedDiff, })), }; // Create work session in database (stores in WorkSession and WorkSessionChange tables) await apiClient.createWorkSession(taskId, workSession); // Format description with change summary const description = formatTaskDescription(summary, changes); // Update task with description and status await apiClient.updateTask(taskId, { description, status: 'done', }); // Update branch session activity await branchSessionManager.updateBranchActivity(); // Check if we should suggest PR creation const prSuggestion = await branchSessionManager.suggestPRCreation(); // Remove active session activeSessions.delete(taskId); let completionMessage = `✅ 作業セッションを完了しました。\n- ファイル変更: ${changes.statistics.filesChanged}個\n- 追加: +${changes.statistics.linesAdded}行\n- 削除: -${changes.statistics.linesRemoved}行\n\nタスク説明とメタデータを更新しました。`; // Add PR suggestion if available if (prSuggestion) { completionMessage += `\n\n${prSuggestion}`; } return { success: true, message: completionMessage, changes: workSession, }; } catch (error: any) { return { success: false, message: `Failed to complete work session: ${error.message}`, }; } } /** * Get active work sessions */ export function getActiveSessions(): WorkSession[] { return Array.from(activeSessions.values()); } /** * Cancel a work session */ export async function cancelWorkSession(taskId: string): Promise<{ success: boolean; message: string; }> { const session = activeSessions.get(taskId); if (!session) { return { success: false, message: `No active work session found for task ${taskId}.`, }; } try { const apiClient = getAPIClient(); // Revert task status back to todo await apiClient.updateTask(taskId, { status: 'todo', }); // Remove active session activeSessions.delete(taskId); return { success: true, message: `Cancelled work session for task ${taskId}.`, }; } catch (error: any) { return { success: false, message: `Failed to cancel work session: ${error.message}`, }; } }

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/mazemaze/mcp-server'

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