feat(show): add comma-separated ID support for multi-task viewing
- Enhanced get-task/show command to support comma-separated task IDs for efficient batch operations. - New features include multiple task retrieval, smart display logic, interactive action menu with batch operations, MCP array response for AI agent efficiency, and support for mixed parent tasks and subtasks. - Implementation includes updated CLI show command, enhanced MCP get_task tool, modified showTaskDirect function, and maintained full backward compatibility. - Documentation updated across all relevant files. Benefits include faster context gathering for AI agents, improved workflow with interactive batch operations, better UX with responsive layout, and enhanced API efficiency.
This commit is contained in:
@@ -9,7 +9,7 @@ Welcome to the Task Master documentation. Use the links below to navigate to the
|
||||
|
||||
## Reference
|
||||
|
||||
- [Command Reference](command-reference.md) - Complete list of all available commands (including research and multi-task viewing)
|
||||
- [Command Reference](command-reference.md) - Complete list of all available commands (including new multi-task viewing)
|
||||
- [Task Structure](task-structure.md) - Understanding the task format and features
|
||||
|
||||
## Examples & Licensing
|
||||
|
||||
@@ -73,6 +73,7 @@ import {
|
||||
displayModelConfiguration,
|
||||
displayAvailableModels,
|
||||
displayApiKeyStatus,
|
||||
displayAiUsageSummary,
|
||||
displayMultipleTasksSummary
|
||||
} from './ui.js';
|
||||
|
||||
@@ -1444,7 +1445,7 @@ function registerCommands(programInstance) {
|
||||
'Additional custom context to include in the research prompt'
|
||||
)
|
||||
.option(
|
||||
'--project-tree',
|
||||
'-t, --tree',
|
||||
'Include project file tree structure in the research context'
|
||||
)
|
||||
.option(
|
||||
@@ -1578,7 +1579,7 @@ function registerCommands(programInstance) {
|
||||
taskIds: taskIds,
|
||||
filePaths: filePaths,
|
||||
customContext: options.context ? options.context.trim() : null,
|
||||
includeProjectTree: !!options.projectTree,
|
||||
includeProjectTree: !!options.tree,
|
||||
saveTarget: options.save ? options.save.trim() : null,
|
||||
detailLevel: options.detail ? options.detail.toLowerCase() : 'medium',
|
||||
tasksPath: tasksPath,
|
||||
|
||||
@@ -2333,7 +2333,7 @@ async function displayMultipleTasksSummary(
|
||||
boxen(
|
||||
chalk.white.bold('Interactive Options:') +
|
||||
'\n' +
|
||||
chalk.cyan('• Press Enter to view detailed breakdown of all tasks') +
|
||||
chalk.cyan('• Press Enter to view available actions for all tasks') +
|
||||
'\n' +
|
||||
chalk.cyan(
|
||||
'• Type a task ID (e.g., "3" or "3.2") to view that specific task'
|
||||
@@ -2364,40 +2364,123 @@ async function displayMultipleTasksSummary(
|
||||
if (choice.toLowerCase() === 'q') {
|
||||
return;
|
||||
} else if (choice.trim() === '') {
|
||||
// Show detailed breakdown of all tasks
|
||||
console.log('\n' + chalk.blue('='.repeat(terminalWidth - 10)));
|
||||
console.log(chalk.white.bold('Detailed Task Breakdown'));
|
||||
console.log(chalk.blue('='.repeat(terminalWidth - 10)) + '\n');
|
||||
// Show action menu for selected tasks
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold('Available Actions for Selected Tasks:') +
|
||||
'\n' +
|
||||
chalk.cyan('1.') +
|
||||
' Mark all as in-progress' +
|
||||
'\n' +
|
||||
chalk.cyan('2.') +
|
||||
' Mark all as done' +
|
||||
'\n' +
|
||||
chalk.cyan('3.') +
|
||||
' Show next available task' +
|
||||
'\n' +
|
||||
chalk.cyan('4.') +
|
||||
' Expand all tasks (generate subtasks)' +
|
||||
'\n' +
|
||||
chalk.cyan('5.') +
|
||||
' View dependency relationships' +
|
||||
'\n' +
|
||||
chalk.cyan('6.') +
|
||||
' Generate task files' +
|
||||
'\n' +
|
||||
chalk.gray('Or type a task ID to view details'),
|
||||
{
|
||||
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
||||
borderColor: 'blue',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
for (let i = 0; i < foundTasks.length; i++) {
|
||||
const task = foundTasks[i];
|
||||
console.log(chalk.cyan.bold(`Task ${task.id}: ${task.title}`));
|
||||
console.log(
|
||||
chalk.gray(
|
||||
`Status: ${task.status || 'pending'} | Priority: ${task.priority || 'medium'}`
|
||||
)
|
||||
);
|
||||
const rl2 = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
if (task.description) {
|
||||
const actionChoice = await new Promise((resolve) => {
|
||||
rl2.question(chalk.cyan('Choose action (1-6): '), resolve);
|
||||
});
|
||||
rl2.close();
|
||||
|
||||
const taskIdList = foundTasks.map((t) => t.id).join(',');
|
||||
|
||||
switch (actionChoice.trim()) {
|
||||
case '1':
|
||||
console.log(
|
||||
chalk.white(`Description: ${truncate(task.description, 80)}`)
|
||||
chalk.blue(
|
||||
`\n→ Command: task-master set-status --id=${taskIdList} --status=in-progress`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Show subtask progress if exists
|
||||
if (task.subtasks && task.subtasks.length > 0) {
|
||||
const total = task.subtasks.length;
|
||||
const completed = task.subtasks.filter(
|
||||
(st) => st.status === 'done' || st.status === 'completed'
|
||||
).length;
|
||||
console.log(
|
||||
chalk.magenta(`Subtasks: ${completed}/${total} completed`)
|
||||
chalk.green(
|
||||
'✓ Copy and run this command to mark all tasks as in-progress'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (i < foundTasks.length - 1) {
|
||||
console.log(chalk.gray('─'.repeat(Math.min(50, terminalWidth - 10))));
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
console.log(
|
||||
chalk.blue(
|
||||
`\n→ Command: task-master set-status --id=${taskIdList} --status=done`
|
||||
)
|
||||
);
|
||||
console.log(
|
||||
chalk.green('✓ Copy and run this command to mark all tasks as done')
|
||||
);
|
||||
break;
|
||||
case '3':
|
||||
console.log(chalk.blue(`\n→ Command: task-master next`));
|
||||
console.log(
|
||||
chalk.green(
|
||||
'✓ Copy and run this command to see the next available task'
|
||||
)
|
||||
);
|
||||
break;
|
||||
case '4':
|
||||
console.log(
|
||||
chalk.blue(
|
||||
`\n→ Command: task-master expand --id=${taskIdList} --research`
|
||||
)
|
||||
);
|
||||
console.log(
|
||||
chalk.green(
|
||||
'✓ Copy and run this command to expand all selected tasks into subtasks'
|
||||
)
|
||||
);
|
||||
break;
|
||||
case '5':
|
||||
// Show dependency visualization
|
||||
console.log(chalk.white.bold('\nDependency Relationships:'));
|
||||
let hasDependencies = false;
|
||||
foundTasks.forEach((task) => {
|
||||
if (task.dependencies && task.dependencies.length > 0) {
|
||||
console.log(
|
||||
chalk.cyan(
|
||||
`Task ${task.id} depends on: ${task.dependencies.join(', ')}`
|
||||
)
|
||||
);
|
||||
hasDependencies = true;
|
||||
}
|
||||
});
|
||||
if (!hasDependencies) {
|
||||
console.log(chalk.gray('No dependencies found for selected tasks'));
|
||||
}
|
||||
break;
|
||||
case '6':
|
||||
console.log(chalk.blue(`\n→ Command: task-master generate`));
|
||||
console.log(
|
||||
chalk.green('✓ Copy and run this command to generate task files')
|
||||
);
|
||||
break;
|
||||
default:
|
||||
if (actionChoice.trim().length > 0) {
|
||||
console.log(chalk.yellow(`Invalid choice: ${actionChoice.trim()}`));
|
||||
console.log(chalk.gray('Please choose 1-6 or type a task ID'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Show specific task
|
||||
|
||||
Reference in New Issue
Block a user