feat(cache): Implement caching for listTasks MCP endpoint

Implemented LRU caching for the  function to improve performance for repeated requests.

Key changes include:
- Added  dependency.
- Introduced a reusable  utility function in  leveraging a .
- Refactored  in  to use the caching utility with a key based on task path, filter, and subtask flag.
- Modified  to include the  boolean flag in the final JSON response structure, nesting the original data under a  key.
- Added  function and corresponding MCP tool () for monitoring cache performance.
- Improved error handling in  for cases where  is not found.

This addresses the previous issue of the empty task list likely caused by stale cache entries and provides clear visibility into whether a response is served from the cache.

Relates to #23.9
This commit is contained in:
Eyal Toledano
2025-03-30 02:25:24 -04:00
parent c4b8fa509b
commit a10ea076d8
10 changed files with 712 additions and 80 deletions

View File

@@ -997,16 +997,16 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
displayBanner();
}
const data = readJSON(tasksPath);
const data = readJSON(tasksPath); // Reads the whole tasks.json
if (!data || !data.tasks) {
throw new Error(`No valid tasks found in ${tasksPath}`);
}
// Filter tasks by status if specified
const filteredTasks = statusFilter
const filteredTasks = statusFilter && statusFilter.toLowerCase() !== 'all' // <-- Added check for 'all'
? data.tasks.filter(task =>
task.status && task.status.toLowerCase() === statusFilter.toLowerCase())
: data.tasks;
: data.tasks; // Default to all tasks if no filter or filter is 'all'
// Calculate completion statistics
const totalTasks = data.tasks.length;
@@ -1039,7 +1039,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
// For JSON output, return structured data
if (outputFormat === 'json') {
// *** Modification: Remove 'details' field for JSON output ***
const tasksWithoutDetails = filteredTasks.map(task => {
const tasksWithoutDetails = filteredTasks.map(task => { // <-- USES filteredTasks!
// Omit 'details' from the parent task
const { details, ...taskRest } = task;
@@ -1055,8 +1055,8 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
// *** End of Modification ***
return {
tasks: tasksWithoutDetails, // Return the modified tasks
filter: statusFilter,
tasks: tasksWithoutDetails, // <--- THIS IS THE ARRAY BEING RETURNED
filter: statusFilter || 'all', // Return the actual filter used
stats: {
total: totalTasks,
completed: doneCount,