From fcc2351b3de3cdb70d532c995e4b002ba09799f8 Mon Sep 17 00:00:00 2001 From: Eyal Toledano Date: Fri, 13 Jun 2025 03:33:14 -0400 Subject: [PATCH] feat(tags): Complete tag support for remaining CLI commands - Add --tag flag to update, move, and set-status commands - Ensure all task operation commands now support tag context - Fix missing tag context passing to core functions - Complete comprehensive tag-aware command coverage --- .taskmaster/state.json | 2 +- scripts/modules/commands.js | 58 ++++++++++++++++++++++++++++++++----- scripts/modules/ui.js | 27 ++++++++++++++++- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/.taskmaster/state.json b/.taskmaster/state.json index 19cd79e2..4fec369e 100644 --- a/.taskmaster/state.json +++ b/.taskmaster/state.json @@ -1,6 +1,6 @@ { "currentTag": "master", - "lastSwitched": "2025-06-13T07:11:05.210Z", + "lastSwitched": "2025-06-13T07:32:07.706Z", "branchTagMapping": {}, "migrationNoticeShown": true } \ No newline at end of file diff --git a/scripts/modules/commands.js b/scripts/modules/commands.js index ce924388..953830e1 100644 --- a/scripts/modules/commands.js +++ b/scripts/modules/commands.js @@ -18,7 +18,9 @@ import { readJSON, writeJSON, findProjectRoot, - getCurrentTag + getCurrentTag, + detectCamelCaseFlags, + toKebabCase } from './utils.js'; import { parsePRD, @@ -72,7 +74,8 @@ import { import { COMPLEXITY_REPORT_FILE, PRD_FILE, - TASKMASTER_TASKS_FILE + TASKMASTER_TASKS_FILE, + TASKMASTER_CONFIG_FILE } from '../../src/constants/paths.js'; import { @@ -90,7 +93,8 @@ import { displayApiKeyStatus, displayAiUsageSummary, displayMultipleTasksSummary, - displayTaggedTasksFYI + displayTaggedTasksFYI, + displayCurrentTagIndicator } from './ui.js'; import { initializeProject } from '../init.js'; @@ -845,11 +849,19 @@ function registerCommands(programInstance) { '-r, --research', 'Use Perplexity AI for research-backed task updates' ) + .option('--tag ', 'Specify tag context for task operations') .action(async (options) => { const tasksPath = options.file || TASKMASTER_TASKS_FILE; const fromId = parseInt(options.from, 10); // Validation happens here const prompt = options.prompt; const useResearch = options.research || false; + const tag = options.tag; + + const projectRoot = findProjectRoot(); + if (!projectRoot) { + console.error(chalk.red('Error: Could not find project root.')); + process.exit(1); + } // Check if there's an 'id' option which is a common mistake (instead of 'from') if ( @@ -896,13 +908,13 @@ function registerCommands(programInstance) { ); } - // Call core updateTasks, passing empty context for CLI + // Call core updateTasks, passing context for CLI await updateTasks( tasksPath, fromId, prompt, useResearch, - {} // Pass empty context + { projectRoot, tag } // Pass context with projectRoot and tag ); }); @@ -1292,10 +1304,12 @@ function registerCommands(programInstance) { 'Path to the tasks file', TASKMASTER_TASKS_FILE ) + .option('--tag ', 'Specify tag context for task operations') .action(async (options) => { const tasksPath = options.file || TASKMASTER_TASKS_FILE; const taskId = options.id; const status = options.status; + const tag = options.tag; if (!taskId || !status) { console.error(chalk.red('Error: Both --id and --status are required')); @@ -1323,7 +1337,7 @@ function registerCommands(programInstance) { process.exit(1); } - await setTaskStatus(tasksPath, taskId, status, { projectRoot }); + await setTaskStatus(tasksPath, taskId, status, { projectRoot, tag }); }); // list command @@ -1356,6 +1370,9 @@ function registerCommands(programInstance) { const withSubtasks = options.withSubtasks || false; const tag = options.tag || getCurrentTag(projectRoot) || 'master'; + // Show current tag context + displayCurrentTagIndicator(tag); + console.log(chalk.blue(`Listing tasks from: ${tasksPath}`)); if (statusFilter) { console.log(chalk.blue(`Filtering by status: ${statusFilter}`)); @@ -1410,6 +1427,9 @@ function registerCommands(programInstance) { const tasksPath = path.resolve(projectRoot, options.file); // Resolve tasks path const tag = options.tag; + // Show current tag context + displayCurrentTagIndicator(tag || getCurrentTag(projectRoot) || 'master'); + if (options.all) { // --- Handle expand --all --- console.log(chalk.blue('Expanding all pending tasks...')); @@ -1518,6 +1538,9 @@ function registerCommands(programInstance) { // Use the provided tag, or the current active tag, or default to 'master' const targetTag = tag || getCurrentTag(projectRoot) || 'master'; + // Show current tag context + displayCurrentTagIndicator(targetTag); + // Tag-aware output file naming: master -> task-complexity-report.json, other tags -> task-complexity-report_tagname.json const outputPath = options.output === COMPLEXITY_REPORT_FILE && targetTag !== 'master' @@ -1674,6 +1697,9 @@ function registerCommands(programInstance) { const tasksPath = options.file || path.join(projectRoot, 'tasks', 'tasks.json'); + // Show current tag context + displayCurrentTagIndicator(tag); + // Validate tasks file exists if task IDs are specified if (taskIds.length > 0) { try { @@ -1826,6 +1852,9 @@ ${result.result} process.exit(1); } + // Show current tag context + displayCurrentTagIndicator(tag || getCurrentTag(projectRoot) || 'master'); + if (!taskIds && !all) { console.error( chalk.red( @@ -1914,6 +1943,11 @@ ${result.result} process.exit(1); } + // Show current tag context + displayCurrentTagIndicator( + options.tag || getCurrentTag(projectRoot) || 'master' + ); + let manualTaskData = null; if (isManualCreation) { manualTaskData = { @@ -2004,6 +2038,9 @@ ${result.result} process.exit(1); } + // Show current tag context + displayCurrentTagIndicator(tag || getCurrentTag(projectRoot) || 'master'); + await displayNextTask(tasksPath, reportPath, { projectRoot, tag }); }); @@ -2041,6 +2078,9 @@ ${result.result} const statusFilter = options.status; const tag = options.tag; + // Show current tag context + displayCurrentTagIndicator(tag || getCurrentTag(projectRoot) || 'master'); + if (!idArg) { console.error(chalk.red('Error: Please provide a task ID')); process.exit(1); @@ -3247,10 +3287,12 @@ Examples: '--to ', 'ID of the destination (e.g., "7" or "7.3"). Must match the number of source IDs if comma-separated' ) + .option('--tag ', 'Specify tag context for task operations') .action(async (options) => { const tasksPath = options.file || TASKMASTER_TASKS_FILE; const sourceId = options.from; const destinationId = options.to; + const tag = options.tag; if (!sourceId || !destinationId) { console.error( @@ -3328,7 +3370,7 @@ Examples: fromId, toId, i === sourceIds.length - 1, - { projectRoot } + { projectRoot, tag } ); console.log( chalk.green( @@ -3358,7 +3400,7 @@ Examples: sourceId, destinationId, true, - { projectRoot } + { projectRoot, tag } ); console.log( chalk.green( diff --git a/scripts/modules/ui.js b/scripts/modules/ui.js index a5b035dd..aaead7cc 100644 --- a/scripts/modules/ui.js +++ b/scripts/modules/ui.js @@ -58,6 +58,30 @@ function displayTaggedTasksFYI(data) { ); } +/** + * Display a small, non-intrusive indicator showing the current tag context + * @param {string} tagName - The tag name to display + * @param {Object} options - Display options + * @param {boolean} [options.skipIfMaster=true] - Don't show indicator if tag is 'master' + * @param {boolean} [options.dim=false] - Use dimmed styling + */ +function displayCurrentTagIndicator(tag, options = {}) { + if (isSilentMode()) return; + + const { skipIfMaster = true, dim = false } = options; + + // Skip display for master tag by default (since it's the default context) + if (skipIfMaster && tag === 'master') return; + + // Create a small, tasteful tag indicator + const tagIcon = '🏷️'; + const tagText = dim + ? chalk.gray(`${tagIcon} tag: ${tag}`) + : chalk.dim(`${tagIcon} tag: `) + chalk.cyan(tag); + + console.log(tagText); +} + /** * Display a fancy banner for the CLI */ @@ -2720,5 +2744,6 @@ export { failLoadingIndicator, warnLoadingIndicator, infoLoadingIndicator, - displayContextAnalysis + displayContextAnalysis, + displayCurrentTagIndicator };