feat(move-tasks): Implement move command for tasks and subtasks
Adds a new CLI command and MCP tool to reorganize tasks and subtasks within the hierarchy. Features include: - Moving tasks between different positions in the task list - Converting tasks to subtasks and vice versa - Moving subtasks between parents - Moving multiple tasks at once with comma-separated IDs - Creating placeholder tasks when moving to new IDs - Validation to prevent accidental data loss This is particularly useful for resolving merge conflicts when multiple team members create tasks on different branches.
This commit is contained in:
93
mcp-server/src/core/direct-functions/move-task.js
Normal file
93
mcp-server/src/core/direct-functions/move-task.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Direct function wrapper for moveTask
|
||||
*/
|
||||
|
||||
import { moveTask } from '../../../../scripts/modules/task-manager.js';
|
||||
import { findTasksJsonPath } from '../utils/path-utils.js';
|
||||
import {
|
||||
enableSilentMode,
|
||||
disableSilentMode
|
||||
} from '../../../../scripts/modules/utils.js';
|
||||
|
||||
/**
|
||||
* Move a task or subtask to a new position
|
||||
* @param {Object} args - Function arguments
|
||||
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file
|
||||
* @param {string} args.sourceId - ID of the task/subtask to move (e.g., '5' or '5.2')
|
||||
* @param {string} args.destinationId - ID of the destination (e.g., '7' or '7.3')
|
||||
* @param {string} args.file - Alternative path to the tasks.json file
|
||||
* @param {string} args.projectRoot - Project root directory
|
||||
* @param {Object} log - Logger object
|
||||
* @returns {Promise<{success: boolean, data?: Object, error?: Object}>}
|
||||
*/
|
||||
export async function moveTaskDirect(args, log, context = {}) {
|
||||
const { session } = context;
|
||||
|
||||
// Validate required parameters
|
||||
if (!args.sourceId) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Source ID is required',
|
||||
code: 'MISSING_SOURCE_ID'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!args.destinationId) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Destination ID is required',
|
||||
code: 'MISSING_DESTINATION_ID'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// Find tasks.json path if not provided
|
||||
let tasksPath = args.tasksJsonPath || args.file;
|
||||
if (!tasksPath) {
|
||||
if (!args.projectRoot) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Project root is required if tasksJsonPath is not provided',
|
||||
code: 'MISSING_PROJECT_ROOT'
|
||||
}
|
||||
};
|
||||
}
|
||||
tasksPath = findTasksJsonPath(args, log);
|
||||
}
|
||||
|
||||
// Enable silent mode to prevent console output during MCP operation
|
||||
enableSilentMode();
|
||||
|
||||
// Call the core moveTask function, always generate files
|
||||
const result = await moveTask(tasksPath, args.sourceId, args.destinationId, true);
|
||||
|
||||
// Restore console output
|
||||
disableSilentMode();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
movedTask: result.movedTask,
|
||||
message: `Successfully moved task/subtask ${args.sourceId} to ${args.destinationId}`
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
// Restore console output in case of error
|
||||
disableSilentMode();
|
||||
|
||||
log.error(`Failed to move task: ${error.message}`);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: error.message,
|
||||
code: 'MOVE_TASK_ERROR'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user