feat(ui): add tag indicator to all CLI commands

- shows 🏷️ tag: tagname for complete context visibility across 15+ commands
This commit is contained in:
Eyal Toledano
2025-06-13 03:51:49 -04:00
parent fcc2351b3d
commit 9d755b9e79
4 changed files with 74 additions and 18 deletions

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": minor
---
Adds tag to CLI output so you know which tag you are performing operations on. Already supported in the MCP response.

View File

@@ -1,6 +1,6 @@
{
"currentTag": "master",
"lastSwitched": "2025-06-13T07:32:07.706Z",
"currentTag": "test-prd-tag",
"lastSwitched": "2025-06-13T07:48:41.146Z",
"branchTagMapping": {},
"migrationNoticeShown": true
}

View File

@@ -699,7 +699,6 @@ function registerCommands(programInstance) {
const force = options.force || false;
const append = options.append || false;
const research = options.research || false;
const tag = options.tag;
let useForce = force;
const useAppend = append;
@@ -709,6 +708,12 @@ function registerCommands(programInstance) {
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
// Helper function to check if there are existing tasks in the target tag and confirm overwrite
async function confirmOverwriteIfNeeded() {
// Check if there are existing tasks in the target tag
@@ -855,7 +860,6 @@ function registerCommands(programInstance) {
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) {
@@ -863,6 +867,12 @@ function registerCommands(programInstance) {
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
// Check if there's an 'id' option which is a common mistake (instead of 'from')
if (
process.argv.includes('--id') ||
@@ -942,7 +952,6 @@ function registerCommands(programInstance) {
.action(async (options) => {
try {
const tasksPath = options.file || TASKMASTER_TASKS_FILE;
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
@@ -950,6 +959,12 @@ function registerCommands(programInstance) {
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
// Validate required parameters
if (!options.id) {
console.error(chalk.red('Error: --id parameter is required'));
@@ -1108,7 +1123,6 @@ function registerCommands(programInstance) {
.action(async (options) => {
try {
const tasksPath = options.file || TASKMASTER_TASKS_FILE;
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
@@ -1116,6 +1130,12 @@ function registerCommands(programInstance) {
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
// Validate required parameters
if (!options.id) {
console.error(chalk.red('Error: --id parameter is required'));
@@ -2133,7 +2153,6 @@ ${result.result}
const tasksPath = options.file || TASKMASTER_TASKS_FILE;
const taskId = options.id;
const dependencyId = options.dependsOn;
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
@@ -2141,6 +2160,12 @@ ${result.result}
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
if (!taskId || !dependencyId) {
console.error(
chalk.red('Error: Both --id and --depends-on are required')
@@ -2179,7 +2204,6 @@ ${result.result}
const tasksPath = options.file || TASKMASTER_TASKS_FILE;
const taskId = options.id;
const dependencyId = options.dependsOn;
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
@@ -2187,6 +2211,12 @@ ${result.result}
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
if (!taskId || !dependencyId) {
console.error(
chalk.red('Error: Both --id and --depends-on are required')
@@ -2227,13 +2257,18 @@ ${result.result}
)
.option('--tag <tag>', 'Specify tag context for task operations')
.action(async (options) => {
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
console.error(chalk.red('Error: Could not find project root.'));
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
await validateDependenciesCommand(options.file || TASKMASTER_TASKS_FILE, {
context: { projectRoot, tag }
});
@@ -2250,13 +2285,18 @@ ${result.result}
)
.option('--tag <tag>', 'Specify tag context for task operations')
.action(async (options) => {
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
console.error(chalk.red('Error: Could not find project root.'));
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
await fixDependenciesCommand(options.file || TASKMASTER_TASKS_FILE, {
context: { projectRoot, tag }
});
@@ -2273,8 +2313,6 @@ ${result.result}
)
.option('--tag <tag>', 'Specify tag context for task operations')
.action(async (options) => {
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
console.error(chalk.red('Error: Could not find project root.'));
@@ -2282,7 +2320,10 @@ ${result.result}
}
// Use the provided tag, or the current active tag, or default to 'master'
const targetTag = tag || getCurrentTag(projectRoot) || 'master';
const targetTag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(targetTag);
// Tag-aware report file naming: master -> task-complexity-report.json, other tags -> task-complexity-report_tagname.json
const reportPath =
@@ -2328,7 +2369,12 @@ ${result.result}
const parentId = options.parent;
const existingTaskId = options.taskId;
const generateFiles = !options.skipGenerate;
const tag = options.tag;
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
if (!parentId) {
console.error(
@@ -2769,7 +2815,6 @@ ${result.result}
.action(async (options) => {
const tasksPath = options.file || TASKMASTER_TASKS_FILE;
const taskIdsString = options.id;
const tag = options.tag;
const projectRoot = findProjectRoot();
if (!projectRoot) {
@@ -2777,6 +2822,12 @@ ${result.result}
process.exit(1);
}
// Resolve tag using standard pattern
const tag = options.tag || getCurrentTag(projectRoot) || 'master';
// Show current tag context
displayCurrentTagIndicator(tag);
if (!taskIdsString) {
console.error(chalk.red('Error: Task ID(s) are required'));
console.error(

View File

@@ -62,15 +62,15 @@ 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.skipIfMaster=false] - 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;
const { skipIfMaster = false, dim = false } = options;
// Skip display for master tag by default (since it's the default context)
// Skip display for master tag only if explicitly requested
if (skipIfMaster && tag === 'master') return;
// Create a small, tasteful tag indicator