diff --git a/.taskmaster/tasks/task_103.txt b/.taskmaster/tasks/task_103.txt index f534c39d..fafbeb9e 100644 --- a/.taskmaster/tasks/task_103.txt +++ b/.taskmaster/tasks/task_103.txt @@ -164,13 +164,13 @@ STATE MANAGEMENT: Updated scripts/init.js to create state.json during initializa ### Details: Test all workflows for legacy users and ensure no regressions. -## 9. Update Documentation and Help Menus [pending] +## 9. Update Documentation and Help Menus [done] ### Dependencies: 103.4, 103.5, 103.6, 103.8 ### Description: Revise user documentation, migration notes, and CLI help menus to reflect new tag-related features and usage patterns, specifically documenting the add-tag command. ### Details: Provide clear instructions and examples for all tag management features, ensuring add-tag command is properly documented with consistent naming. -## 10. Conduct Comprehensive System Testing and QA [pending] +## 10. Conduct Comprehensive System Testing and QA [done] ### Dependencies: 103.8, 103.9 ### Description: Perform end-to-end testing of the tagged task lists system, including migration, tag management, task operations, and context switching. ### Details: diff --git a/.taskmaster/tasks/task_106.txt b/.taskmaster/tasks/task_105.txt similarity index 99% rename from .taskmaster/tasks/task_106.txt rename to .taskmaster/tasks/task_105.txt index 8c0dcb88..cb906c84 100644 --- a/.taskmaster/tasks/task_106.txt +++ b/.taskmaster/tasks/task_105.txt @@ -1,4 +1,4 @@ -# Task ID: 106 +# Task ID: 105 # Title: Implement Fun Easter Egg Commands for Developer Delight # Status: pending # Dependencies: 2, 4 diff --git a/.taskmaster/tasks/tasks.json b/.taskmaster/tasks/tasks.json index 629c8bf9..3eec4c20 100644 --- a/.taskmaster/tasks/tasks.json +++ b/.taskmaster/tasks/tasks.json @@ -6587,7 +6587,7 @@ 8 ], "details": "Provide clear instructions and examples for all tag management features, ensuring add-tag command is properly documented with consistent naming.", - "status": "pending", + "status": "done", "testStrategy": "Review documentation for completeness and clarity; user acceptance testing." }, { @@ -6599,7 +6599,7 @@ 9 ], "details": "Ensure all features work as intended and meet quality standards, with specific focus on add-tag command functionality.", - "status": "pending", + "status": "done", "testStrategy": "Execute test cases covering all user scenarios, including edge cases and error handling." }, { @@ -6710,7 +6710,7 @@ ] }, { - "id": 106, + "id": 105, "title": "Implement Fun Easter Egg Commands for Developer Delight", "description": "Add playful easter egg commands to the CLI that provide entertainment and stress relief for developers while maintaining the professional nature of the tool.", "details": "## Core Problem Statement\n\nDevelopers often work long hours and need moments of levity to maintain productivity and morale. Adding fun, non-intrusive easter egg commands can:\n\n1. **Boost Developer Morale**: Provide moments of humor and surprise during intense work sessions\n2. **Showcase Tool Personality**: Give Task Master a friendly, approachable character\n3. **Create Community Engagement**: Fun features often become talking points and increase tool adoption\n4. **Stress Relief**: Offer quick mental breaks without leaving the development environment\n\n## Implementation Approach\n\n1. **Add Easter Egg Commands**: Implement hidden/fun commands in commands.js:\n - `fortune` - Display random programming wisdom or motivational quotes\n - `joke` - Show developer-friendly programming jokes\n - `zen` - Display programming zen principles (like Python's zen)\n - `coffee` - ASCII art coffee cup with brewing animation\n - `rubber-duck` - Rubber duck debugging assistant with encouraging messages\n - `praise` - Random praise messages for completed tasks\n\n2. **Command Structure**: Follow existing CLI patterns but make commands discoverable through:\n - Hidden help section (accessible via `--fun` flag on help command)\n - Occasional hints when users complete milestones or long work sessions\n\n3. **Content Management**: Create a separate `easter-eggs.js` module containing:\n - Arrays of quotes, jokes, zen principles\n - ASCII art templates\n - Motivational messages\n - Randomization logic for content selection\n\n4. **Integration Points**:\n - Add subtle hints after task completions (\"Try 'task coffee' for a break!\")\n - Include fun stats in status displays (e.g., \"You've completed X tasks - that deserves a joke!\")\n - Optional daily/weekly fun fact notifications\n\n5. **Configuration**: Add optional config settings:\n - `enableEasterEggs` (default: true)\n - `funNotificationFrequency` (never, rare, occasional, frequent)\n - `favoriteEasterEgg` for personalized defaults\n\n6. **ASCII Art and Animations**: Implement simple text-based animations:\n - Coffee brewing progress bars\n - Rubber duck \"thinking\" animations\n - Celebration ASCII art for major milestones", diff --git a/scripts/modules/commands.js b/scripts/modules/commands.js index f6aa5792..dad68d79 100644 --- a/scripts/modules/commands.js +++ b/scripts/modules/commands.js @@ -1249,7 +1249,14 @@ function registerCommands(programInstance) { chalk.blue(`Setting status of task(s) ${taskId} to: ${status}`) ); - await setTaskStatus(tasksPath, taskId, status); + // Find project root for tag resolution + const projectRoot = findProjectRoot(); + if (!projectRoot) { + console.error(chalk.red('Error: Could not find project root.')); + process.exit(1); + } + + await setTaskStatus(tasksPath, taskId, status, { projectRoot }); }); // list command @@ -1269,6 +1276,12 @@ function registerCommands(programInstance) { .option('-s, --status ', 'Filter by status') .option('--with-subtasks', 'Show subtasks for each task') .action(async (options) => { + const projectRoot = findProjectRoot(); + if (!projectRoot) { + console.error(chalk.red('Error: Could not find project root.')); + process.exit(1); + } + const tasksPath = options.file || TASKMASTER_TASKS_FILE; const reportPath = options.report; const statusFilter = options.status; @@ -1282,7 +1295,15 @@ function registerCommands(programInstance) { console.log(chalk.blue('Including subtasks in listing')); } - await listTasks(tasksPath, statusFilter, reportPath, withSubtasks); + await listTasks( + tasksPath, + statusFilter, + reportPath, + withSubtasks, + 'text', + null, + { projectRoot } + ); }); // expand command diff --git a/scripts/modules/task-manager/list-tasks.js b/scripts/modules/task-manager/list-tasks.js index b7754bbf..bddc2e0b 100644 --- a/scripts/modules/task-manager/list-tasks.js +++ b/scripts/modules/task-manager/list-tasks.js @@ -27,6 +27,7 @@ import { * @param {boolean} withSubtasks - Whether to show subtasks * @param {string} outputFormat - Output format (text or json) * @param {string} tag - Optional tag to override current tag resolution + * @param {Object} context - Optional context object containing projectRoot and other options * @returns {Object} - Task list result for json format */ function listTasks( @@ -35,10 +36,13 @@ function listTasks( reportPath = null, withSubtasks = false, outputFormat = 'text', - tag = null + tag = null, + context = {} ) { try { - const data = readJSON(tasksPath, null, tag); // Pass tag to readJSON + // Extract projectRoot from context if provided + const projectRoot = context.projectRoot || null; + const data = readJSON(tasksPath, projectRoot, tag); // Pass projectRoot to readJSON if (!data || !data.tasks) { throw new Error(`No valid tasks found in ${tasksPath}`); } diff --git a/scripts/modules/task-manager/set-task-status.js b/scripts/modules/task-manager/set-task-status.js index a06b2c5a..23147b80 100644 --- a/scripts/modules/task-manager/set-task-status.js +++ b/scripts/modules/task-manager/set-task-status.js @@ -2,7 +2,14 @@ import path from 'path'; import chalk from 'chalk'; import boxen from 'boxen'; -import { log, readJSON, writeJSON, findTaskById } from '../utils.js'; +import { + log, + readJSON, + writeJSON, + findTaskById, + getCurrentTag, + ensureTagMetadata +} from '../utils.js'; import { displayBanner } from '../ui.js'; import { validateTaskDependencies } from '../dependency-manager.js'; import { getDebugFlag } from '../config-manager.js'; @@ -18,7 +25,7 @@ import { * @param {string} tasksPath - Path to the tasks.json file * @param {string} taskIdInput - Task ID(s) to update * @param {string} newStatus - New status - * @param {Object} options - Additional options (mcpLog for MCP mode) + * @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot for tag resolution) * @param {string} tag - Optional tag to override current tag resolution * @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode */ @@ -50,7 +57,37 @@ async function setTaskStatus( } log('info', `Reading tasks from ${tasksPath}...`); - const data = readJSON(tasksPath, null, tag); + + // Read the raw data without tag resolution to preserve tagged structure + let rawData = readJSON(tasksPath, options.projectRoot); // No tag parameter + + // Handle the case where readJSON returns resolved data with _rawTaggedData + if (rawData && rawData._rawTaggedData) { + // Use the raw tagged data and discard the resolved view + rawData = rawData._rawTaggedData; + } + + // Determine the current tag + const currentTag = tag || getCurrentTag(options.projectRoot) || 'master'; + + // Ensure the tag exists in the raw data + if ( + !rawData || + !rawData[currentTag] || + !Array.isArray(rawData[currentTag].tasks) + ) { + throw new Error( + `Invalid tasks file or tag "${currentTag}" not found at ${tasksPath}` + ); + } + + // Get the tasks for the current tag + const data = { + tasks: rawData[currentTag].tasks, + tag: currentTag, + _rawTaggedData: rawData + }; + if (!data || !data.tasks) { throw new Error(`No valid tasks found in ${tasksPath}`); } @@ -65,8 +102,17 @@ async function setTaskStatus( updatedTasks.push(id); } - // Write the updated tasks to the file - writeJSON(tasksPath, data); + // Update the raw data structure with the modified tasks + rawData[currentTag].tasks = data.tasks; + + // Ensure the tag has proper metadata + ensureTagMetadata(rawData[currentTag], { + description: `Tasks for ${currentTag} context` + }); + + // Write the updated raw data back to the file + // The writeJSON function will automatically filter out _rawTaggedData + writeJSON(tasksPath, rawData); // Validate dependencies after status update log('info', 'Validating dependencies after status update...'); diff --git a/scripts/modules/utils.js b/scripts/modules/utils.js index 033467eb..d9d598bf 100644 --- a/scripts/modules/utils.js +++ b/scripts/modules/utils.js @@ -234,14 +234,55 @@ function readJSON(filepath, projectRoot = null, tag = null) { return null; } - // If it's not a tasks.json file or already in legacy format, return as-is - if (!filepath.includes('tasks.json') || !data || Array.isArray(data.tasks)) { + // If it's not a tasks.json file, return as-is + if (!filepath.includes('tasks.json') || !data) { if (isDebug) { - console.log(`File is not tagged format or is legacy, returning as-is`); + console.log(`File is not tasks.json or data is null, returning as-is`); } return data; } + // Check if this is legacy format that needs migration + if (Array.isArray(data.tasks)) { + if (isDebug) { + console.log(`File is in legacy format, performing migration...`); + } + + // This is legacy format - migrate it to tagged format + const migratedData = { + master: { + tasks: data.tasks, + metadata: data.metadata || { + created: new Date().toISOString(), + updated: new Date().toISOString(), + description: 'Tasks for master context' + } + } + }; + + // Write the migrated data back to the file + try { + writeJSON(filepath, migratedData); + if (isDebug) { + console.log(`Successfully migrated legacy format to tagged format`); + } + + // Perform complete migration (config.json, state.json) + performCompleteTagMigration(filepath); + + // Mark for migration notice + markMigrationForNotice(filepath); + } catch (writeError) { + if (isDebug) { + console.log(`Error writing migrated data: ${writeError.message}`); + } + // If write fails, continue with the original data + } + + // Continue processing with the migrated data structure + data = migratedData; + } + // If we have tagged data, we need to resolve which tag to use if (typeof data === 'object' && !data.tasks) { // This is tagged format