Skip to main content
Glama

MCP Prompt Enhancer

by soniankur948
TaskTracker.ts12.1 kB
/** * TaskTracker * * Analyzes and tracks task context including: * - Task type inference from prompts * - Focus area detection * - Working files tracking * - Recent actions history */ import * as path from 'path'; import logger from '../utils/Logger'; // Task types that can be inferred export enum TaskType { CREATION = 'creation', DEBUGGING = 'debugging', REFACTORING = 'refactoring', STYLING = 'styling', TESTING = 'testing', DOCUMENTATION = 'documentation', ANALYSIS = 'analysis', API = 'api', GENERAL = 'general' } // Focus areas within the codebase export enum FocusArea { FRONTEND = 'frontend', BACKEND = 'backend', DATABASE = 'database', AUTHENTICATION = 'authentication', COMPONENTS = 'components', STATE = 'state', ROUTING = 'routing', STYLING = 'styling', TESTING = 'testing', DEPLOYMENT = 'deployment', GENERAL = 'general' } // Task action history item export interface TaskAction { timestamp: number; action: string; files?: string[]; description: string; } // Task context information export interface TaskContext { taskType: TaskType; focusArea: FocusArea; relevantFiles: string[]; currentPrompt: string; recentActions: TaskAction[]; taskStartTime: number; } // Keywords for task type detection const TASK_TYPE_KEYWORDS: Record<TaskType, string[]> = { [TaskType.CREATION]: [ 'create', 'new', 'add', 'implement', 'build', 'generate', 'make' ], [TaskType.DEBUGGING]: [ 'debug', 'fix', 'issue', 'bug', 'error', 'problem', 'crash', 'not working' ], [TaskType.REFACTORING]: [ 'refactor', 'improve', 'optimize', 'clean', 'restructure', 'enhance', 'rewrite' ], [TaskType.STYLING]: [ 'style', 'css', 'design', 'layout', 'ui', 'appearance', 'look', 'theme' ], [TaskType.TESTING]: [ 'test', 'unit test', 'integration test', 'e2e', 'end-to-end', 'testing', 'jest', 'spec' ], [TaskType.DOCUMENTATION]: [ 'document', 'comment', 'readme', 'docs', 'documentation', 'explain' ], [TaskType.ANALYSIS]: [ 'analyze', 'review', 'check', 'evaluate', 'assess', 'examine' ], [TaskType.API]: [ 'api', 'endpoint', 'request', 'response', 'fetch', 'http', 'rest', 'graphql' ], [TaskType.GENERAL]: [ 'help', 'how', 'what', 'guide', 'learn', 'understand' ] }; // Keywords for focus area detection const FOCUS_AREA_KEYWORDS: Record<FocusArea, string[]> = { [FocusArea.FRONTEND]: [ 'component', 'react', 'vue', 'angular', 'ui', 'interface', 'jsx', 'tsx', 'html' ], [FocusArea.BACKEND]: [ 'server', 'api', 'endpoint', 'controller', 'service', 'middleware', 'express', 'node' ], [FocusArea.DATABASE]: [ 'database', 'db', 'model', 'schema', 'query', 'sql', 'nosql', 'mongo', 'postgres' ], [FocusArea.AUTHENTICATION]: [ 'auth', 'login', 'register', 'user', 'permission', 'role', 'jwt', 'session' ], [FocusArea.COMPONENTS]: [ 'component', 'button', 'form', 'input', 'modal', 'menu', 'navigation', 'sidebar' ], [FocusArea.STATE]: [ 'state', 'store', 'redux', 'context', 'recoil', 'zustand', 'mobx', 'useState' ], [FocusArea.ROUTING]: [ 'route', 'router', 'navigation', 'link', 'path', 'url', 'history', 'params' ], [FocusArea.STYLING]: [ 'css', 'scss', 'style', 'tailwind', 'theme', 'layout', 'responsive', 'design' ], [FocusArea.TESTING]: [ 'test', 'jest', 'enzyme', 'testing-library', 'cypress', 'selenium', 'unit', 'e2e' ], [FocusArea.DEPLOYMENT]: [ 'deploy', 'build', 'ci', 'cd', 'pipeline', 'docker', 'kubernetes', 'aws', 'cloud' ], [FocusArea.GENERAL]: [ 'general', 'help', 'guide', 'project', 'setup', 'configuration' ] }; // File extension to focus area mapping const FILE_EXTENSION_FOCUS: Record<string, FocusArea> = { '.jsx': FocusArea.FRONTEND, '.tsx': FocusArea.FRONTEND, '.js': FocusArea.GENERAL, '.ts': FocusArea.GENERAL, '.css': FocusArea.STYLING, '.scss': FocusArea.STYLING, '.html': FocusArea.FRONTEND, '.json': FocusArea.GENERAL, '.md': FocusArea.GENERAL, // Changed from DOCUMENTATION which doesn't exist in enum '.test.js': FocusArea.TESTING, '.test.ts': FocusArea.TESTING, '.spec.js': FocusArea.TESTING, '.spec.ts': FocusArea.TESTING, }; export class TaskTracker { private currentTask: TaskContext; private log = logger.createChildLogger('TaskTracker'); private maxRecentActions: number; constructor(initialTaskType: TaskType = TaskType.GENERAL) { this.maxRecentActions = 10; // Initialize with default task context this.currentTask = { taskType: initialTaskType, focusArea: FocusArea.GENERAL, relevantFiles: [], currentPrompt: '', recentActions: [], taskStartTime: Date.now(), }; this.log.info(`Task tracker initialized with task type: ${initialTaskType}`); } /** * Get current task context */ public getTaskContext(): TaskContext { return { ...this.currentTask }; } /** * Reset task context with a new task */ public resetTask(taskType?: TaskType, prompt?: string): void { this.currentTask = { taskType: taskType || TaskType.GENERAL, focusArea: FocusArea.GENERAL, relevantFiles: [], currentPrompt: prompt || '', recentActions: [], taskStartTime: Date.now(), }; this.log.info(`Task context reset with task type: ${this.currentTask.taskType}`); // Infer task details if prompt is provided if (prompt) { this.updateFromPrompt(prompt); } } /** * Update task context based on a new prompt */ public updateFromPrompt(prompt: string): TaskContext { this.log.debug('Updating task context from prompt'); // Save the current prompt this.currentTask.currentPrompt = prompt; // Infer task type if not explicitly set if (this.currentTask.taskType === TaskType.GENERAL) { this.currentTask.taskType = this.inferTaskType(prompt); this.log.debug(`Inferred task type: ${this.currentTask.taskType}`); } // Infer focus area this.currentTask.focusArea = this.inferFocusArea(prompt); this.log.debug(`Inferred focus area: ${this.currentTask.focusArea}`); // Extract potential file references this.extractFileReferences(prompt); return this.getTaskContext(); } /** * Infer the type of task from a prompt */ public inferTaskType(prompt: string): TaskType { const normalizedPrompt = prompt.toLowerCase(); // Calculate scores for each task type based on keyword matches const scores: Record<TaskType, number> = Object.values(TaskType).reduce((acc, type) => { acc[type] = 0; return acc; }, {} as Record<TaskType, number>); // Check for keywords for each task type for (const [taskType, keywords] of Object.entries(TASK_TYPE_KEYWORDS)) { for (const keyword of keywords) { if (normalizedPrompt.includes(keyword.toLowerCase())) { scores[taskType as TaskType] += 1; } } } // Find the task type with the highest score let bestMatch = TaskType.GENERAL; let highestScore = 0; for (const [type, score] of Object.entries(scores)) { if (score > highestScore) { highestScore = score; bestMatch = type as TaskType; } } return bestMatch; } /** * Infer the focus area from a prompt */ public inferFocusArea(prompt: string): FocusArea { const normalizedPrompt = prompt.toLowerCase(); // Calculate scores for each focus area based on keyword matches const scores: Record<FocusArea, number> = Object.values(FocusArea).reduce((acc, area) => { acc[area] = 0; return acc; }, {} as Record<FocusArea, number>); // Check for keywords for each focus area for (const [area, keywords] of Object.entries(FOCUS_AREA_KEYWORDS)) { for (const keyword of keywords) { if (normalizedPrompt.includes(keyword.toLowerCase())) { scores[area as FocusArea] += 1; } } } // Find the focus area with the highest score let bestMatch = FocusArea.GENERAL; let highestScore = 0; for (const [area, score] of Object.entries(scores)) { if (score > highestScore) { highestScore = score; bestMatch = area as FocusArea; } } return bestMatch; } /** * Extract file references from a prompt */ private extractFileReferences(prompt: string): void { // Simple file path extraction with common extensions const filePathRegex = /[\w/.-]+\.(js|jsx|ts|tsx|css|scss|html|json|md|py|java|rb|go|php)/g; const matches = prompt.match(filePathRegex) || []; // Add extracted files to relevant files if not already there for (const match of matches) { if (!this.currentTask.relevantFiles.includes(match)) { this.currentTask.relevantFiles.push(match); this.log.debug(`Added relevant file from prompt: ${match}`); } } } /** * Record a new action in the task history */ public recordAction(action: string, files?: string[], description?: string): void { const taskAction: TaskAction = { timestamp: Date.now(), action, files, description: description || action }; // Add to recent actions, maintaining max size this.currentTask.recentActions.unshift(taskAction); if (this.currentTask.recentActions.length > this.maxRecentActions) { this.currentTask.recentActions = this.currentTask.recentActions.slice(0, this.maxRecentActions); } // Add files to relevant files list if not already there if (files) { for (const file of files) { if (!this.currentTask.relevantFiles.includes(file)) { this.currentTask.relevantFiles.push(file); } } } this.log.debug(`Recorded action: ${action}`); } /** * Add relevant files to the task context */ public addRelevantFiles(files: string[]): void { for (const file of files) { if (!this.currentTask.relevantFiles.includes(file)) { this.currentTask.relevantFiles.push(file); // Update focus area based on file extension if current area is general if (this.currentTask.focusArea === FocusArea.GENERAL) { const ext = path.extname(file); if (FILE_EXTENSION_FOCUS[ext]) { this.currentTask.focusArea = FILE_EXTENSION_FOCUS[ext]; this.log.debug(`Updated focus area to ${this.currentTask.focusArea} based on file extension`); } } } } this.log.debug(`Added relevant files: ${files.join(', ')}`); } /** * Explicitly set the task type */ public setTaskType(taskType: TaskType): void { this.currentTask.taskType = taskType; this.log.info(`Task type explicitly set to: ${taskType}`); } /** * Explicitly set the focus area */ public setFocusArea(focusArea: FocusArea): void { this.currentTask.focusArea = focusArea; this.log.info(`Focus area explicitly set to: ${focusArea}`); } /** * Get task duration in seconds */ public getTaskDuration(): number { return Math.floor((Date.now() - this.currentTask.taskStartTime) / 1000); } /** * Generate a summary of the current task context */ public generateTaskSummary(): string { const { taskType, focusArea, relevantFiles, recentActions } = this.currentTask; const duration = this.getTaskDuration(); let summary = `Task Type: ${taskType}\n`; summary += `Focus Area: ${focusArea}\n`; summary += `Duration: ${duration} seconds\n\n`; if (relevantFiles.length > 0) { summary += `Relevant Files:\n${relevantFiles.join('\n')}\n\n`; } if (recentActions.length > 0) { summary += 'Recent Actions:\n'; for (const action of recentActions) { const timeAgo = Math.floor((Date.now() - action.timestamp) / 1000); summary += `- ${action.description} (${timeAgo}s ago)\n`; } } return summary; } } export default TaskTracker;

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/soniankur948/prompt-enhancer'

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