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:
Eyal Toledano
2025-05-25 19:39:23 -04:00
parent 325f5a2aa3
commit 1e020023ed
12 changed files with 299 additions and 141 deletions

View File

@@ -66,32 +66,91 @@ export async function showTaskDirect(args, log) {
const complexityReport = readComplexityReport(reportPath);
const { task, originalSubtaskCount } = findTaskById(
tasksData.tasks,
id,
complexityReport,
status
);
// Parse comma-separated IDs
const taskIds = id
.split(',')
.map((taskId) => taskId.trim())
.filter((taskId) => taskId.length > 0);
if (!task) {
if (taskIds.length === 0) {
return {
success: false,
error: {
code: 'TASK_NOT_FOUND',
message: `Task or subtask with ID ${id} not found`
code: 'INVALID_TASK_ID',
message: 'No valid task IDs provided'
}
};
}
log.info(`Successfully retrieved task ${id}.`);
// Handle single task ID (existing behavior)
if (taskIds.length === 1) {
const { task, originalSubtaskCount } = findTaskById(
tasksData.tasks,
taskIds[0],
complexityReport,
status
);
const returnData = { ...task };
if (originalSubtaskCount !== null) {
returnData._originalSubtaskCount = originalSubtaskCount;
returnData._subtaskFilter = status;
if (!task) {
return {
success: false,
error: {
code: 'TASK_NOT_FOUND',
message: `Task or subtask with ID ${taskIds[0]} not found`
}
};
}
log.info(`Successfully retrieved task ${taskIds[0]}.`);
const returnData = { ...task };
if (originalSubtaskCount !== null) {
returnData._originalSubtaskCount = originalSubtaskCount;
returnData._subtaskFilter = status;
}
return { success: true, data: returnData };
}
return { success: true, data: returnData };
// Handle multiple task IDs
const foundTasks = [];
const notFoundIds = [];
taskIds.forEach((taskId) => {
const { task, originalSubtaskCount } = findTaskById(
tasksData.tasks,
taskId,
complexityReport,
status
);
if (task) {
const taskData = { ...task };
if (originalSubtaskCount !== null) {
taskData._originalSubtaskCount = originalSubtaskCount;
taskData._subtaskFilter = status;
}
foundTasks.push(taskData);
} else {
notFoundIds.push(taskId);
}
});
log.info(
`Successfully retrieved ${foundTasks.length} of ${taskIds.length} requested tasks.`
);
// Return multiple tasks with metadata
return {
success: true,
data: {
tasks: foundTasks,
requestedIds: taskIds,
foundCount: foundTasks.length,
notFoundIds: notFoundIds,
isMultiple: true
}
};
} catch (error) {
log.error(`Error showing task ${id}: ${error.message}`);
return {

View File

@@ -44,7 +44,11 @@ export function registerShowTaskTool(server) {
name: 'get_task',
description: 'Get detailed information about a specific task',
parameters: z.object({
id: z.string().describe('Task ID to get'),
id: z
.string()
.describe(
'Task ID(s) to get (can be comma-separated for multiple tasks)'
),
status: z
.string()
.optional()
@@ -66,7 +70,7 @@ export function registerShowTaskTool(server) {
'Absolute path to the project root directory (Optional, usually from session)'
)
}),
execute: withNormalizedProjectRoot(async (args, { log }) => {
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
const { id, file, status, projectRoot } = args;
try {
@@ -110,7 +114,8 @@ export function registerShowTaskTool(server) {
status: status,
projectRoot: projectRoot
},
log
log,
{ session }
);
if (result.success) {