TaskTracker.js•14.2 kB
"use strict";
/**
* TaskTracker
*
* Analyzes and tracks task context including:
* - Task type inference from prompts
* - Focus area detection
* - Working files tracking
* - Recent actions history
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskTracker = exports.FocusArea = exports.TaskType = void 0;
const path = __importStar(require("path"));
const Logger_1 = __importDefault(require("../utils/Logger"));
// Task types that can be inferred
var TaskType;
(function (TaskType) {
TaskType["CREATION"] = "creation";
TaskType["DEBUGGING"] = "debugging";
TaskType["REFACTORING"] = "refactoring";
TaskType["STYLING"] = "styling";
TaskType["TESTING"] = "testing";
TaskType["DOCUMENTATION"] = "documentation";
TaskType["ANALYSIS"] = "analysis";
TaskType["API"] = "api";
TaskType["GENERAL"] = "general";
})(TaskType || (exports.TaskType = TaskType = {}));
// Focus areas within the codebase
var FocusArea;
(function (FocusArea) {
FocusArea["FRONTEND"] = "frontend";
FocusArea["BACKEND"] = "backend";
FocusArea["DATABASE"] = "database";
FocusArea["AUTHENTICATION"] = "authentication";
FocusArea["COMPONENTS"] = "components";
FocusArea["STATE"] = "state";
FocusArea["ROUTING"] = "routing";
FocusArea["STYLING"] = "styling";
FocusArea["TESTING"] = "testing";
FocusArea["DEPLOYMENT"] = "deployment";
FocusArea["GENERAL"] = "general";
})(FocusArea || (exports.FocusArea = FocusArea = {}));
// Keywords for task type detection
const TASK_TYPE_KEYWORDS = {
[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 = {
[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 = {
'.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,
};
class TaskTracker {
constructor(initialTaskType = TaskType.GENERAL) {
this.log = Logger_1.default.createChildLogger('TaskTracker');
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
*/
getTaskContext() {
return { ...this.currentTask };
}
/**
* Reset task context with a new task
*/
resetTask(taskType, prompt) {
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
*/
updateFromPrompt(prompt) {
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
*/
inferTaskType(prompt) {
const normalizedPrompt = prompt.toLowerCase();
// Calculate scores for each task type based on keyword matches
const scores = Object.values(TaskType).reduce((acc, type) => {
acc[type] = 0;
return acc;
}, {});
// 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] += 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;
}
}
return bestMatch;
}
/**
* Infer the focus area from a prompt
*/
inferFocusArea(prompt) {
const normalizedPrompt = prompt.toLowerCase();
// Calculate scores for each focus area based on keyword matches
const scores = Object.values(FocusArea).reduce((acc, area) => {
acc[area] = 0;
return acc;
}, {});
// 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] += 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;
}
}
return bestMatch;
}
/**
* Extract file references from a prompt
*/
extractFileReferences(prompt) {
// 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
*/
recordAction(action, files, description) {
const 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
*/
addRelevantFiles(files) {
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
*/
setTaskType(taskType) {
this.currentTask.taskType = taskType;
this.log.info(`Task type explicitly set to: ${taskType}`);
}
/**
* Explicitly set the focus area
*/
setFocusArea(focusArea) {
this.currentTask.focusArea = focusArea;
this.log.info(`Focus area explicitly set to: ${focusArea}`);
}
/**
* Get task duration in seconds
*/
getTaskDuration() {
return Math.floor((Date.now() - this.currentTask.taskStartTime) / 1000);
}
/**
* Generate a summary of the current task context
*/
generateTaskSummary() {
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;
}
}
exports.TaskTracker = TaskTracker;
exports.default = TaskTracker;
//# sourceMappingURL=TaskTracker.js.map