feat(tagged-tasks): Complete core tag management system implementation

- Implements comprehensive tagged task lists system for multi-context task management including core tag management functions (Task 103.11), MCP integration updates, and foundational infrastructure for tagged task operations. Features tag CRUD operations, validation, metadata tracking, deep task copying, and full backward compatibility.
This commit is contained in:
Eyal Toledano
2025-06-12 03:40:13 -04:00
parent a84cd1a492
commit 75e017e371
32 changed files with 1907 additions and 60726 deletions

View File

@@ -231,9 +231,24 @@ function readJSON(filepath, projectRoot = null) {
filepath.includes('tasks.json')
) {
// This is legacy format - migrate to tagged format
// Get file creation/modification date for the master tag
let createdDate;
try {
const stats = fs.statSync(filepath);
// Use the earlier of creation time or modification time
createdDate =
stats.birthtime < stats.mtime ? stats.birthtime : stats.mtime;
} catch (error) {
// Fallback to current date if we can't get file stats
createdDate = new Date();
}
const migratedData = {
master: {
tasks: data.tasks
tasks: data.tasks,
description: 'Tasks live here by default',
created: createdDate.toISOString(),
taskCount: data.tasks ? data.tasks.length : 0
}
};
@@ -312,22 +327,25 @@ function readJSON(filepath, projectRoot = null) {
resolvedTag = 'master';
}
// Store the raw tagged data BEFORE modifying data
const rawTaggedData = { ...data };
// Return the tasks for the resolved tag, or master as fallback, or empty array
if (data[resolvedTag] && data[resolvedTag].tasks) {
data = {
tag: resolvedTag,
tasks: data[resolvedTag].tasks,
_rawTaggedData: data
_rawTaggedData: rawTaggedData
};
} else if (data.master && data.master.tasks) {
data = {
tag: 'master',
tasks: data.master.tasks,
_rawTaggedData: data
_rawTaggedData: rawTaggedData
};
} else {
// No valid tags found, return empty
data = { tasks: [], tag: 'master', _rawTaggedData: data };
data = { tasks: [], tag: 'master', _rawTaggedData: rawTaggedData };
}
}
}
@@ -512,7 +530,16 @@ function writeJSON(filepath, data) {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf8');
// Clean the data before writing - remove internal properties that should not be persisted
let cleanData = data;
if (data && typeof data === 'object' && data._rawTaggedData !== undefined) {
// Create a clean copy without internal properties using destructuring
const { _rawTaggedData, ...cleanedData } = data;
cleanData = cleanedData;
}
fs.writeFileSync(filepath, JSON.stringify(cleanData, null, 2), 'utf8');
} catch (error) {
log('error', `Error writing JSON file ${filepath}:`, error.message);
if (isDebug) {