Compare commits
31 Commits
next
...
add-comple
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
834dfb86ac | ||
|
|
b984af0606 | ||
|
|
d7ebfe30fc | ||
|
|
126abb9631 | ||
|
|
e917fd16c0 | ||
|
|
07a710d88e | ||
|
|
0ca41443de | ||
|
|
7c543cd8c3 | ||
|
|
c2865b81f8 | ||
|
|
a0ac50ffd7 | ||
|
|
b6b0dd1e29 | ||
|
|
0f37cf0851 | ||
|
|
abb5063b3e | ||
|
|
6b0ec458e8 | ||
|
|
8047ec756c | ||
|
|
be8fe8092f | ||
|
|
33d2569ace | ||
|
|
fdbb25e185 | ||
|
|
deaf4a6ff4 | ||
|
|
3628acab78 | ||
|
|
463de0035c | ||
|
|
fffcc5a89d | ||
|
|
11506ddc0e | ||
|
|
dcb3f2f9f9 | ||
|
|
e045a5268c | ||
|
|
8911bf4d49 | ||
|
|
5e5e20391a | ||
|
|
521cf0e5f0 | ||
|
|
92bd0e4395 | ||
|
|
3162ac49ec | ||
|
|
b98af1541e |
5
.changeset/social-masks-fold.md
Normal file
5
.changeset/social-masks-fold.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'task-master-ai': minor
|
||||
---
|
||||
|
||||
Display task complexity scores in task lists, next task, and task details views.
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
*/
|
||||
export async function listTasksDirect(args, log) {
|
||||
// Destructure the explicit tasksJsonPath from args
|
||||
const { tasksJsonPath, status, withSubtasks } = args;
|
||||
const { tasksJsonPath, reportPath, status, withSubtasks } = args;
|
||||
|
||||
if (!tasksJsonPath) {
|
||||
log.error('listTasksDirect called without tasksJsonPath');
|
||||
@@ -49,6 +49,7 @@ export async function listTasksDirect(args, log) {
|
||||
const resultData = listTasks(
|
||||
tasksJsonPath,
|
||||
statusFilter,
|
||||
reportPath,
|
||||
withSubtasksFilter,
|
||||
'json'
|
||||
);
|
||||
@@ -63,6 +64,7 @@ export async function listTasksDirect(args, log) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
log.info(
|
||||
`Core listTasks function retrieved ${resultData.tasks.length} tasks`
|
||||
);
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
*/
|
||||
|
||||
import { findNextTask } from '../../../../scripts/modules/task-manager.js';
|
||||
import { readJSON } from '../../../../scripts/modules/utils.js';
|
||||
import {
|
||||
readJSON,
|
||||
readComplexityReport
|
||||
} from '../../../../scripts/modules/utils.js';
|
||||
import {
|
||||
enableSilentMode,
|
||||
disableSilentMode
|
||||
@@ -20,7 +23,7 @@ import {
|
||||
*/
|
||||
export async function nextTaskDirect(args, log) {
|
||||
// Destructure expected args
|
||||
const { tasksJsonPath } = args;
|
||||
const { tasksJsonPath, reportPath } = args;
|
||||
|
||||
if (!tasksJsonPath) {
|
||||
log.error('nextTaskDirect called without tasksJsonPath');
|
||||
@@ -55,8 +58,11 @@ export async function nextTaskDirect(args, log) {
|
||||
};
|
||||
}
|
||||
|
||||
// Read the complexity report
|
||||
const complexityReport = readComplexityReport(reportPath);
|
||||
|
||||
// Find the next task
|
||||
const nextTask = findNextTask(data.tasks);
|
||||
const nextTask = findNextTask(data.tasks, complexityReport);
|
||||
|
||||
if (!nextTask) {
|
||||
log.info(
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
* Direct function implementation for showing task details
|
||||
*/
|
||||
|
||||
import { findTaskById, readJSON } from '../../../../scripts/modules/utils.js';
|
||||
import {
|
||||
findTaskById,
|
||||
readComplexityReport,
|
||||
readJSON
|
||||
} from '../../../../scripts/modules/utils.js';
|
||||
import { findTasksJsonPath } from '../utils/path-utils.js';
|
||||
|
||||
/**
|
||||
@@ -12,6 +16,7 @@ import { findTasksJsonPath } from '../utils/path-utils.js';
|
||||
* @param {Object} args - Command arguments.
|
||||
* @param {string} args.id - Task ID to show.
|
||||
* @param {string} [args.file] - Optional path to the tasks file (passed to findTasksJsonPath).
|
||||
* @param {string} args.reportPath - Explicit path to the complexity report file.
|
||||
* @param {string} [args.status] - Optional status to filter subtasks by.
|
||||
* @param {string} args.projectRoot - Absolute path to the project root directory (already normalized by tool).
|
||||
* @param {Object} log - Logger object.
|
||||
@@ -22,7 +27,7 @@ export async function showTaskDirect(args, log) {
|
||||
// Destructure session from context if needed later, otherwise ignore
|
||||
// const { session } = context;
|
||||
// Destructure projectRoot and other args. projectRoot is assumed normalized.
|
||||
const { id, file, status, projectRoot } = args;
|
||||
const { id, file, reportPath, status, projectRoot } = args;
|
||||
|
||||
log.info(
|
||||
`Showing task direct function. ID: ${id}, File: ${file}, Status Filter: ${status}, ProjectRoot: ${projectRoot}`
|
||||
@@ -59,9 +64,12 @@ export async function showTaskDirect(args, log) {
|
||||
};
|
||||
}
|
||||
|
||||
const complexityReport = readComplexityReport(reportPath);
|
||||
|
||||
const { task, originalSubtaskCount } = findTaskById(
|
||||
tasksData.tasks,
|
||||
id,
|
||||
complexityReport,
|
||||
status
|
||||
);
|
||||
|
||||
|
||||
@@ -339,6 +339,49 @@ export function findPRDDocumentPath(projectRoot, explicitPath, log) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findComplexityReportPath(projectRoot, explicitPath, log) {
|
||||
// If explicit path is provided, check if it exists
|
||||
if (explicitPath) {
|
||||
const fullPath = path.isAbsolute(explicitPath)
|
||||
? explicitPath
|
||||
: path.resolve(projectRoot, explicitPath);
|
||||
|
||||
if (fs.existsSync(fullPath)) {
|
||||
log.info(`Using provided PRD document path: ${fullPath}`);
|
||||
return fullPath;
|
||||
} else {
|
||||
log.warn(
|
||||
`Provided PRD document path not found: ${fullPath}, will search for alternatives`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Common locations and file patterns for PRD documents
|
||||
const commonLocations = [
|
||||
'', // Project root
|
||||
'scripts/'
|
||||
];
|
||||
|
||||
const commonFileNames = [
|
||||
'complexity-report.json',
|
||||
'task-complexity-report.json'
|
||||
];
|
||||
|
||||
// Check all possible combinations
|
||||
for (const location of commonLocations) {
|
||||
for (const fileName of commonFileNames) {
|
||||
const potentialPath = path.join(projectRoot, location, fileName);
|
||||
if (fs.existsSync(potentialPath)) {
|
||||
log.info(`Found PRD document at: ${potentialPath}`);
|
||||
return potentialPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.warn(`No PRD document found in common locations within ${projectRoot}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the tasks output directory path
|
||||
* @param {string} projectRoot - The project root directory
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
withNormalizedProjectRoot
|
||||
} from './utils.js';
|
||||
import { showTaskDirect } from '../core/task-master-core.js';
|
||||
import { findTasksJsonPath } from '../core/utils/path-utils.js';
|
||||
import {
|
||||
findTasksJsonPath,
|
||||
findComplexityReportPath
|
||||
} from '../core/utils/path-utils.js';
|
||||
|
||||
/**
|
||||
* Custom processor function that removes allTasks from the response
|
||||
@@ -50,6 +53,12 @@ export function registerShowTaskTool(server) {
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Path to the tasks file relative to project root'),
|
||||
complexityReport: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Path to the complexity report file (relative to project root or absolute)'
|
||||
),
|
||||
projectRoot: z
|
||||
.string()
|
||||
.optional()
|
||||
@@ -81,9 +90,22 @@ export function registerShowTaskTool(server) {
|
||||
}
|
||||
|
||||
// Call the direct function, passing the normalized projectRoot
|
||||
// Resolve the path to complexity report
|
||||
let complexityReportPath;
|
||||
try {
|
||||
complexityReportPath = findComplexityReportPath(
|
||||
projectRoot,
|
||||
args.complexityReport,
|
||||
log
|
||||
);
|
||||
} catch (error) {
|
||||
log.error(`Error finding complexity report: ${error.message}`);
|
||||
}
|
||||
const result = await showTaskDirect(
|
||||
{
|
||||
tasksJsonPath: tasksJsonPath,
|
||||
reportPath: complexityReportPath,
|
||||
// Pass other relevant args
|
||||
id: id,
|
||||
status: status,
|
||||
projectRoot: projectRoot
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
withNormalizedProjectRoot
|
||||
} from './utils.js';
|
||||
import { listTasksDirect } from '../core/task-master-core.js';
|
||||
import { findTasksJsonPath } from '../core/utils/path-utils.js';
|
||||
import {
|
||||
findTasksJsonPath,
|
||||
findComplexityReportPath
|
||||
} from '../core/utils/path-utils.js';
|
||||
|
||||
/**
|
||||
* Register the getTasks tool with the MCP server
|
||||
@@ -38,6 +41,12 @@ export function registerListTasksTool(server) {
|
||||
.describe(
|
||||
'Path to the tasks file (relative to project root or absolute)'
|
||||
),
|
||||
complexityReport: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Path to the complexity report file (relative to project root or absolute)'
|
||||
),
|
||||
projectRoot: z
|
||||
.string()
|
||||
.describe('The directory of the project. Must be an absolute path.')
|
||||
@@ -60,11 +69,23 @@ export function registerListTasksTool(server) {
|
||||
);
|
||||
}
|
||||
|
||||
// Resolve the path to complexity report
|
||||
let complexityReportPath;
|
||||
try {
|
||||
complexityReportPath = findComplexityReportPath(
|
||||
args.projectRoot,
|
||||
args.complexityReport,
|
||||
log
|
||||
);
|
||||
} catch (error) {
|
||||
log.error(`Error finding complexity report: ${error.message}`);
|
||||
}
|
||||
const result = await listTasksDirect(
|
||||
{
|
||||
tasksJsonPath: tasksJsonPath,
|
||||
status: args.status,
|
||||
withSubtasks: args.withSubtasks
|
||||
withSubtasks: args.withSubtasks,
|
||||
reportPath: complexityReportPath
|
||||
},
|
||||
log
|
||||
);
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
withNormalizedProjectRoot
|
||||
} from './utils.js';
|
||||
import { nextTaskDirect } from '../core/task-master-core.js';
|
||||
import { findTasksJsonPath } from '../core/utils/path-utils.js';
|
||||
import {
|
||||
findTasksJsonPath,
|
||||
findComplexityReportPath
|
||||
} from '../core/utils/path-utils.js';
|
||||
|
||||
/**
|
||||
* Register the next-task tool with the MCP server
|
||||
@@ -23,6 +26,12 @@ export function registerNextTaskTool(server) {
|
||||
'Find the next task to work on based on dependencies and status',
|
||||
parameters: z.object({
|
||||
file: z.string().optional().describe('Absolute path to the tasks file'),
|
||||
complexityReport: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Path to the complexity report file (relative to project root or absolute)'
|
||||
),
|
||||
projectRoot: z
|
||||
.string()
|
||||
.describe('The directory of the project. Must be an absolute path.')
|
||||
@@ -45,9 +54,21 @@ export function registerNextTaskTool(server) {
|
||||
);
|
||||
}
|
||||
|
||||
// Resolve the path to complexity report
|
||||
let complexityReportPath;
|
||||
try {
|
||||
complexityReportPath = findComplexityReportPath(
|
||||
args.projectRoot,
|
||||
args.complexityReport,
|
||||
log
|
||||
);
|
||||
} catch (error) {
|
||||
log.error(`Error finding complexity report: ${error.message}`);
|
||||
}
|
||||
const result = await nextTaskDirect(
|
||||
{
|
||||
tasksJsonPath: tasksJsonPath
|
||||
tasksJsonPath: tasksJsonPath,
|
||||
reportPath: complexityReportPath
|
||||
},
|
||||
log
|
||||
);
|
||||
|
||||
@@ -1072,10 +1072,16 @@ function registerCommands(programInstance) {
|
||||
.command('list')
|
||||
.description('List all tasks')
|
||||
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
||||
.option(
|
||||
'-r, --report <report>',
|
||||
'Path to the complexity report file',
|
||||
'scripts/task-complexity-report.json'
|
||||
)
|
||||
.option('-s, --status <status>', 'Filter by status')
|
||||
.option('--with-subtasks', 'Show subtasks for each task')
|
||||
.action(async (options) => {
|
||||
const tasksPath = options.file;
|
||||
const reportPath = options.report;
|
||||
const statusFilter = options.status;
|
||||
const withSubtasks = options.withSubtasks || false;
|
||||
|
||||
@@ -1087,7 +1093,7 @@ function registerCommands(programInstance) {
|
||||
console.log(chalk.blue('Including subtasks in listing'));
|
||||
}
|
||||
|
||||
await listTasks(tasksPath, statusFilter, withSubtasks);
|
||||
await listTasks(tasksPath, statusFilter, reportPath, withSubtasks);
|
||||
});
|
||||
|
||||
// expand command
|
||||
@@ -1393,9 +1399,15 @@ function registerCommands(programInstance) {
|
||||
`Show the next task to work on based on dependencies and status${chalk.reset('')}`
|
||||
)
|
||||
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
||||
.option(
|
||||
'-r, --report <report>',
|
||||
'Path to the complexity report file',
|
||||
'scripts/task-complexity-report.json'
|
||||
)
|
||||
.action(async (options) => {
|
||||
const tasksPath = options.file;
|
||||
await displayNextTask(tasksPath);
|
||||
const reportPath = options.report;
|
||||
await displayNextTask(tasksPath, reportPath);
|
||||
});
|
||||
|
||||
// show command
|
||||
@@ -1408,6 +1420,11 @@ function registerCommands(programInstance) {
|
||||
.option('-i, --id <id>', 'Task ID to show')
|
||||
.option('-s, --status <status>', 'Filter subtasks by status') // ADDED status option
|
||||
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
||||
.option(
|
||||
'-r, --report <report>',
|
||||
'Path to the complexity report file',
|
||||
'scripts/task-complexity-report.json'
|
||||
)
|
||||
.action(async (taskId, options) => {
|
||||
const idArg = taskId || options.id;
|
||||
const statusFilter = options.status; // ADDED: Capture status filter
|
||||
@@ -1418,8 +1435,9 @@ function registerCommands(programInstance) {
|
||||
}
|
||||
|
||||
const tasksPath = options.file;
|
||||
const reportPath = options.report;
|
||||
// PASS statusFilter to the display function
|
||||
await displayTaskById(tasksPath, idArg, statusFilter);
|
||||
await displayTaskById(tasksPath, idArg, reportPath, statusFilter);
|
||||
});
|
||||
|
||||
// add-dependency command
|
||||
|
||||
@@ -23,7 +23,7 @@ import updateSubtaskById from './task-manager/update-subtask-by-id.js';
|
||||
import removeTask from './task-manager/remove-task.js';
|
||||
import taskExists from './task-manager/task-exists.js';
|
||||
import isTaskDependentOn from './task-manager/is-task-dependent.js';
|
||||
|
||||
import { readComplexityReport } from './utils.js';
|
||||
// Export task manager functions
|
||||
export {
|
||||
parsePRD,
|
||||
@@ -45,5 +45,6 @@ export {
|
||||
removeTask,
|
||||
findTaskById,
|
||||
taskExists,
|
||||
isTaskDependentOn
|
||||
isTaskDependentOn,
|
||||
readComplexityReport
|
||||
};
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { log } from '../utils.js';
|
||||
import { addComplexityToTask } from '../utils.js';
|
||||
|
||||
/**
|
||||
* Return the next work item:
|
||||
* • Prefer an eligible SUBTASK that belongs to any parent task
|
||||
@@ -15,9 +18,10 @@
|
||||
* ─ parentId → number (present only when it's a subtask)
|
||||
*
|
||||
* @param {Object[]} tasks – full array of top-level tasks, each may contain .subtasks[]
|
||||
* @param {Object} [complexityReport=null] - Optional complexity report object
|
||||
* @returns {Object|null} – next work item or null if nothing is eligible
|
||||
*/
|
||||
function findNextTask(tasks) {
|
||||
function findNextTask(tasks, complexityReport = null) {
|
||||
// ---------- helpers ----------------------------------------------------
|
||||
const priorityValues = { high: 3, medium: 2, low: 1 };
|
||||
|
||||
@@ -91,7 +95,14 @@ function findNextTask(tasks) {
|
||||
if (aPar !== bPar) return aPar - bPar;
|
||||
return aSub - bSub;
|
||||
});
|
||||
return candidateSubtasks[0];
|
||||
const nextTask = candidateSubtasks[0];
|
||||
|
||||
// Add complexity to the task before returning
|
||||
if (nextTask && complexityReport) {
|
||||
addComplexityToTask(nextTask, complexityReport);
|
||||
}
|
||||
|
||||
return nextTask;
|
||||
}
|
||||
|
||||
// ---------- 2) fall back to top-level tasks (original logic) ------------
|
||||
@@ -116,6 +127,11 @@ function findNextTask(tasks) {
|
||||
return a.id - b.id;
|
||||
})[0];
|
||||
|
||||
// Add complexity to the task before returning
|
||||
if (nextTask && complexityReport) {
|
||||
addComplexityToTask(nextTask, complexityReport);
|
||||
}
|
||||
|
||||
return nextTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,20 @@ import chalk from 'chalk';
|
||||
import boxen from 'boxen';
|
||||
import Table from 'cli-table3';
|
||||
|
||||
import { log, readJSON, truncate } from '../utils.js';
|
||||
import {
|
||||
log,
|
||||
readJSON,
|
||||
truncate,
|
||||
readComplexityReport,
|
||||
addComplexityToTask
|
||||
} from '../utils.js';
|
||||
import findNextTask from './find-next-task.js';
|
||||
|
||||
import {
|
||||
displayBanner,
|
||||
getStatusWithColor,
|
||||
formatDependenciesWithStatus,
|
||||
getComplexityWithColor,
|
||||
createProgressBar
|
||||
} from '../ui.js';
|
||||
|
||||
@@ -16,6 +23,7 @@ import {
|
||||
* List all tasks
|
||||
* @param {string} tasksPath - Path to the tasks.json file
|
||||
* @param {string} statusFilter - Filter by status
|
||||
* @param {string} reportPath - Path to the complexity report
|
||||
* @param {boolean} withSubtasks - Whether to show subtasks
|
||||
* @param {string} outputFormat - Output format (text or json)
|
||||
* @returns {Object} - Task list result for json format
|
||||
@@ -23,6 +31,7 @@ import {
|
||||
function listTasks(
|
||||
tasksPath,
|
||||
statusFilter,
|
||||
reportPath = null,
|
||||
withSubtasks = false,
|
||||
outputFormat = 'text'
|
||||
) {
|
||||
@@ -37,6 +46,13 @@ function listTasks(
|
||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||
}
|
||||
|
||||
// Add complexity scores to tasks if report exists
|
||||
const complexityReport = readComplexityReport(reportPath);
|
||||
// Apply complexity scores to tasks
|
||||
if (complexityReport && complexityReport.complexityAnalysis) {
|
||||
data.tasks.forEach((task) => addComplexityToTask(task, complexityReport));
|
||||
}
|
||||
|
||||
// Filter tasks by status if specified
|
||||
const filteredTasks =
|
||||
statusFilter && statusFilter.toLowerCase() !== 'all' // <-- Added check for 'all'
|
||||
@@ -257,8 +273,8 @@ function listTasks(
|
||||
);
|
||||
const avgDependenciesPerTask = totalDependencies / data.tasks.length;
|
||||
|
||||
// Find next task to work on
|
||||
const nextItem = findNextTask(data.tasks);
|
||||
// Find next task to work on, passing the complexity report
|
||||
const nextItem = findNextTask(data.tasks, complexityReport);
|
||||
|
||||
// Get terminal width - more reliable method
|
||||
let terminalWidth;
|
||||
@@ -301,8 +317,11 @@ function listTasks(
|
||||
`${chalk.blue('•')} ${chalk.white('Avg dependencies per task:')} ${avgDependenciesPerTask.toFixed(1)}\n\n` +
|
||||
chalk.cyan.bold('Next Task to Work On:') +
|
||||
'\n' +
|
||||
`ID: ${chalk.cyan(nextItem ? nextItem.id : 'N/A')} - ${nextItem ? chalk.white.bold(truncate(nextItem.title, 40)) : chalk.yellow('No task available')}\n` +
|
||||
`Priority: ${nextItem ? chalk.white(nextItem.priority || 'medium') : ''} Dependencies: ${nextItem ? formatDependenciesWithStatus(nextItem.dependencies, data.tasks, true) : ''}`;
|
||||
`ID: ${chalk.cyan(nextItem ? nextItem.id : 'N/A')} - ${nextItem ? chalk.white.bold(truncate(nextItem.title, 40)) : chalk.yellow('No task available')}
|
||||
` +
|
||||
`Priority: ${nextItem ? chalk.white(nextItem.priority || 'medium') : ''} Dependencies: ${nextItem ? formatDependenciesWithStatus(nextItem.dependencies, data.tasks, true, complexityReport) : ''}
|
||||
` +
|
||||
`Complexity: ${nextItem && nextItem.complexityScore ? getComplexityWithColor(nextItem.complexityScore) : chalk.gray('N/A')}`;
|
||||
|
||||
// Calculate width for side-by-side display
|
||||
// Box borders, padding take approximately 4 chars on each side
|
||||
@@ -412,9 +431,16 @@ function listTasks(
|
||||
// Make dependencies column smaller as requested (-20%)
|
||||
const depsWidthPct = 20;
|
||||
|
||||
const complexityWidthPct = 10;
|
||||
|
||||
// Calculate title/description width as remaining space (+20% from dependencies reduction)
|
||||
const titleWidthPct =
|
||||
100 - idWidthPct - statusWidthPct - priorityWidthPct - depsWidthPct;
|
||||
100 -
|
||||
idWidthPct -
|
||||
statusWidthPct -
|
||||
priorityWidthPct -
|
||||
depsWidthPct -
|
||||
complexityWidthPct;
|
||||
|
||||
// Allow 10 characters for borders and padding
|
||||
const availableWidth = terminalWidth - 10;
|
||||
@@ -424,6 +450,9 @@ function listTasks(
|
||||
const statusWidth = Math.floor(availableWidth * (statusWidthPct / 100));
|
||||
const priorityWidth = Math.floor(availableWidth * (priorityWidthPct / 100));
|
||||
const depsWidth = Math.floor(availableWidth * (depsWidthPct / 100));
|
||||
const complexityWidth = Math.floor(
|
||||
availableWidth * (complexityWidthPct / 100)
|
||||
);
|
||||
const titleWidth = Math.floor(availableWidth * (titleWidthPct / 100));
|
||||
|
||||
// Create a table with correct borders and spacing
|
||||
@@ -433,9 +462,17 @@ function listTasks(
|
||||
chalk.cyan.bold('Title'),
|
||||
chalk.cyan.bold('Status'),
|
||||
chalk.cyan.bold('Priority'),
|
||||
chalk.cyan.bold('Dependencies')
|
||||
chalk.cyan.bold('Dependencies'),
|
||||
chalk.cyan.bold('Complexity')
|
||||
],
|
||||
colWidths: [
|
||||
idWidth,
|
||||
titleWidth,
|
||||
statusWidth,
|
||||
priorityWidth,
|
||||
depsWidth,
|
||||
complexityWidth // Added complexity column width
|
||||
],
|
||||
colWidths: [idWidth, titleWidth, statusWidth, priorityWidth, depsWidth],
|
||||
style: {
|
||||
head: [], // No special styling for header
|
||||
border: [], // No special styling for border
|
||||
@@ -454,7 +491,8 @@ function listTasks(
|
||||
depText = formatDependenciesWithStatus(
|
||||
task.dependencies,
|
||||
data.tasks,
|
||||
true
|
||||
true,
|
||||
complexityReport
|
||||
);
|
||||
} else {
|
||||
depText = chalk.gray('None');
|
||||
@@ -480,7 +518,10 @@ function listTasks(
|
||||
truncate(cleanTitle, titleWidth - 3),
|
||||
status,
|
||||
priorityColor(truncate(task.priority || 'medium', priorityWidth - 2)),
|
||||
depText // No truncation for dependencies
|
||||
depText,
|
||||
task.complexityScore
|
||||
? getComplexityWithColor(task.complexityScore)
|
||||
: chalk.gray('N/A')
|
||||
]);
|
||||
|
||||
// Add subtasks if requested
|
||||
@@ -516,6 +557,8 @@ function listTasks(
|
||||
// Default to regular task dependency
|
||||
const depTask = data.tasks.find((t) => t.id === depId);
|
||||
if (depTask) {
|
||||
// Add complexity to depTask before checking status
|
||||
addComplexityToTask(depTask, complexityReport);
|
||||
const isDone =
|
||||
depTask.status === 'done' || depTask.status === 'completed';
|
||||
const isInProgress = depTask.status === 'in-progress';
|
||||
@@ -541,7 +584,10 @@ function listTasks(
|
||||
chalk.dim(`└─ ${truncate(subtask.title, titleWidth - 5)}`),
|
||||
getStatusWithColor(subtask.status, true),
|
||||
chalk.dim('-'),
|
||||
subtaskDepText // No truncation for dependencies
|
||||
subtaskDepText,
|
||||
subtask.complexityScore
|
||||
? chalk.gray(`${subtask.complexityScore}`)
|
||||
: chalk.gray('N/A')
|
||||
]);
|
||||
});
|
||||
}
|
||||
@@ -597,6 +643,8 @@ function listTasks(
|
||||
subtasksSection = `\n\n${chalk.white.bold('Subtasks:')}\n`;
|
||||
subtasksSection += parentTaskForSubtasks.subtasks
|
||||
.map((subtask) => {
|
||||
// Add complexity to subtask before display
|
||||
addComplexityToTask(subtask, complexityReport);
|
||||
// Using a more simplified format for subtask status display
|
||||
const status = subtask.status || 'pending';
|
||||
const statusColors = {
|
||||
@@ -625,8 +673,8 @@ function listTasks(
|
||||
'\n\n' +
|
||||
// Use nextItem.priority, nextItem.status, nextItem.dependencies
|
||||
`${chalk.white('Priority:')} ${priorityColors[nextItem.priority || 'medium'](nextItem.priority || 'medium')} ${chalk.white('Status:')} ${getStatusWithColor(nextItem.status, true)}\n` +
|
||||
`${chalk.white('Dependencies:')} ${nextItem.dependencies && nextItem.dependencies.length > 0 ? formatDependenciesWithStatus(nextItem.dependencies, data.tasks, true) : chalk.gray('None')}\n\n` +
|
||||
// Use nextItem.description (Note: findNextTask doesn't return description, need to fetch original task/subtask for this)
|
||||
`${chalk.white('Dependencies:')} ${nextItem.dependencies && nextItem.dependencies.length > 0 ? formatDependenciesWithStatus(nextItem.dependencies, data.tasks, true, complexityReport) : chalk.gray('None')}\n\n` +
|
||||
// Use nextTask.description (Note: findNextTask doesn't return description, need to fetch original task/subtask for this)
|
||||
// *** Fetching original item for description and details ***
|
||||
`${chalk.white('Description:')} ${getWorkItemDescription(nextItem, data.tasks)}` +
|
||||
subtasksSection + // <-- Subtasks are handled above now
|
||||
|
||||
@@ -17,7 +17,11 @@ import {
|
||||
isSilentMode
|
||||
} from './utils.js';
|
||||
import fs from 'fs';
|
||||
import { findNextTask, analyzeTaskComplexity } from './task-manager.js';
|
||||
import {
|
||||
findNextTask,
|
||||
analyzeTaskComplexity,
|
||||
readComplexityReport
|
||||
} from './task-manager.js';
|
||||
import { getProjectName, getDefaultSubtasks } from './config-manager.js';
|
||||
import { TASK_STATUS_OPTIONS } from '../../src/constants/task-status.js';
|
||||
import { getTaskMasterVersion } from '../../src/utils/getVersion.js';
|
||||
@@ -264,12 +268,14 @@ function getStatusWithColor(status, forTable = false) {
|
||||
* @param {Array} dependencies - Array of dependency IDs
|
||||
* @param {Array} allTasks - Array of all tasks
|
||||
* @param {boolean} forConsole - Whether the output is for console display
|
||||
* @param {Object|null} complexityReport - Optional pre-loaded complexity report
|
||||
* @returns {string} Formatted dependencies string
|
||||
*/
|
||||
function formatDependenciesWithStatus(
|
||||
dependencies,
|
||||
allTasks,
|
||||
forConsole = false
|
||||
forConsole = false,
|
||||
complexityReport = null // Add complexityReport parameter
|
||||
) {
|
||||
if (
|
||||
!dependencies ||
|
||||
@@ -333,7 +339,11 @@ function formatDependenciesWithStatus(
|
||||
typeof depId === 'string' ? parseInt(depId, 10) : depId;
|
||||
|
||||
// Look up the task using the numeric ID
|
||||
const depTaskResult = findTaskById(allTasks, numericDepId);
|
||||
const depTaskResult = findTaskById(
|
||||
allTasks,
|
||||
numericDepId,
|
||||
complexityReport
|
||||
);
|
||||
const depTask = depTaskResult.task; // Access the task object from the result
|
||||
|
||||
if (!depTask) {
|
||||
@@ -752,7 +762,7 @@ function truncateString(str, maxLength) {
|
||||
* Display the next task to work on
|
||||
* @param {string} tasksPath - Path to the tasks.json file
|
||||
*/
|
||||
async function displayNextTask(tasksPath) {
|
||||
async function displayNextTask(tasksPath, complexityReportPath = null) {
|
||||
displayBanner();
|
||||
|
||||
// Read the tasks file
|
||||
@@ -762,8 +772,11 @@ async function displayNextTask(tasksPath) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Read complexity report once
|
||||
const complexityReport = readComplexityReport(complexityReportPath);
|
||||
|
||||
// Find the next task
|
||||
const nextTask = findNextTask(data.tasks);
|
||||
const nextTask = findNextTask(data.tasks, complexityReport);
|
||||
|
||||
if (!nextTask) {
|
||||
console.log(
|
||||
@@ -824,7 +837,18 @@ async function displayNextTask(tasksPath) {
|
||||
],
|
||||
[
|
||||
chalk.cyan.bold('Dependencies:'),
|
||||
formatDependenciesWithStatus(nextTask.dependencies, data.tasks, true)
|
||||
formatDependenciesWithStatus(
|
||||
nextTask.dependencies,
|
||||
data.tasks,
|
||||
true,
|
||||
complexityReport
|
||||
)
|
||||
],
|
||||
[
|
||||
chalk.cyan.bold('Complexity:'),
|
||||
nextTask.complexityScore
|
||||
? getComplexityWithColor(nextTask.complexityScore)
|
||||
: chalk.gray('N/A')
|
||||
],
|
||||
[chalk.cyan.bold('Description:'), nextTask.description]
|
||||
);
|
||||
@@ -992,7 +1016,12 @@ async function displayNextTask(tasksPath) {
|
||||
* @param {string|number} taskId - The ID of the task to display
|
||||
* @param {string} [statusFilter] - Optional status to filter subtasks by
|
||||
*/
|
||||
async function displayTaskById(tasksPath, taskId, statusFilter = null) {
|
||||
async function displayTaskById(
|
||||
tasksPath,
|
||||
taskId,
|
||||
complexityReportPath = null,
|
||||
statusFilter = null
|
||||
) {
|
||||
displayBanner();
|
||||
|
||||
// Read the tasks file
|
||||
@@ -1002,11 +1031,15 @@ async function displayTaskById(tasksPath, taskId, statusFilter = null) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Read complexity report once
|
||||
const complexityReport = readComplexityReport(complexityReportPath);
|
||||
|
||||
// Find the task by ID, applying the status filter if provided
|
||||
// Returns { task, originalSubtaskCount, originalSubtasks }
|
||||
const { task, originalSubtaskCount, originalSubtasks } = findTaskById(
|
||||
data.tasks,
|
||||
taskId,
|
||||
complexityReport,
|
||||
statusFilter
|
||||
);
|
||||
|
||||
@@ -1061,6 +1094,12 @@ async function displayTaskById(tasksPath, taskId, statusFilter = null) {
|
||||
chalk.cyan.bold('Status:'),
|
||||
getStatusWithColor(task.status || 'pending', true)
|
||||
],
|
||||
[
|
||||
chalk.cyan.bold('Complexity:'),
|
||||
task.complexityScore
|
||||
? getComplexityWithColor(task.complexityScore)
|
||||
: chalk.gray('N/A')
|
||||
],
|
||||
[
|
||||
chalk.cyan.bold('Description:'),
|
||||
task.description || 'No description provided.'
|
||||
@@ -1139,7 +1178,18 @@ async function displayTaskById(tasksPath, taskId, statusFilter = null) {
|
||||
[chalk.cyan.bold('Priority:'), priorityColor(task.priority || 'medium')],
|
||||
[
|
||||
chalk.cyan.bold('Dependencies:'),
|
||||
formatDependenciesWithStatus(task.dependencies, data.tasks, true)
|
||||
formatDependenciesWithStatus(
|
||||
task.dependencies,
|
||||
data.tasks,
|
||||
true,
|
||||
complexityReport
|
||||
)
|
||||
],
|
||||
[
|
||||
chalk.cyan.bold('Complexity:'),
|
||||
task.complexityScore
|
||||
? getComplexityWithColor(task.complexityScore)
|
||||
: chalk.gray('N/A')
|
||||
],
|
||||
[chalk.cyan.bold('Description:'), task.description]
|
||||
);
|
||||
|
||||
@@ -275,6 +275,22 @@ function findTaskInComplexityReport(report, taskId) {
|
||||
return report.complexityAnalysis.find((task) => task.taskId === taskId);
|
||||
}
|
||||
|
||||
function addComplexityToTask(task, complexityReport) {
|
||||
let taskId;
|
||||
if (task.isSubtask) {
|
||||
taskId = task.parentTask.id;
|
||||
} else if (task.parentId) {
|
||||
taskId = task.parentId;
|
||||
} else {
|
||||
taskId = task.id;
|
||||
}
|
||||
|
||||
const taskAnalysis = findTaskInComplexityReport(complexityReport, taskId);
|
||||
if (taskAnalysis) {
|
||||
task.complexityScore = taskAnalysis.complexityScore;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a task exists in the tasks array
|
||||
* @param {Array} tasks - The tasks array
|
||||
@@ -325,10 +341,17 @@ function formatTaskId(id) {
|
||||
* Finds a task by ID in the tasks array. Optionally filters subtasks by status.
|
||||
* @param {Array} tasks - The tasks array
|
||||
* @param {string|number} taskId - The task ID to find
|
||||
* @param {Object|null} complexityReport - Optional pre-loaded complexity report
|
||||
* @returns {Object|null} The task object or null if not found
|
||||
* @param {string} [statusFilter] - Optional status to filter subtasks by
|
||||
* @returns {{task: Object|null, originalSubtaskCount: number|null}} The task object (potentially with filtered subtasks) and the original subtask count if filtered, or nulls if not found.
|
||||
*/
|
||||
function findTaskById(tasks, taskId, statusFilter = null) {
|
||||
function findTaskById(
|
||||
tasks,
|
||||
taskId,
|
||||
complexityReport = null,
|
||||
statusFilter = null
|
||||
) {
|
||||
if (!taskId || !tasks || !Array.isArray(tasks)) {
|
||||
return { task: null, originalSubtaskCount: null };
|
||||
}
|
||||
@@ -356,10 +379,17 @@ function findTaskById(tasks, taskId, statusFilter = null) {
|
||||
subtask.isSubtask = true;
|
||||
}
|
||||
|
||||
// Return the found subtask (or null) and null for originalSubtaskCount
|
||||
// If we found a task, check for complexity data
|
||||
if (subtask && complexityReport) {
|
||||
addComplexityToTask(subtask, complexityReport);
|
||||
}
|
||||
|
||||
return { task: subtask || null, originalSubtaskCount: null };
|
||||
}
|
||||
|
||||
let taskResult = null;
|
||||
let originalSubtaskCount = null;
|
||||
|
||||
// Find the main task
|
||||
const id = parseInt(taskId, 10);
|
||||
const task = tasks.find((t) => t.id === id) || null;
|
||||
@@ -369,6 +399,8 @@ function findTaskById(tasks, taskId, statusFilter = null) {
|
||||
return { task: null, originalSubtaskCount: null };
|
||||
}
|
||||
|
||||
taskResult = task;
|
||||
|
||||
// If task found and statusFilter provided, filter its subtasks
|
||||
if (statusFilter && task.subtasks && Array.isArray(task.subtasks)) {
|
||||
const originalSubtaskCount = task.subtasks.length;
|
||||
@@ -379,12 +411,18 @@ function findTaskById(tasks, taskId, statusFilter = null) {
|
||||
subtask.status &&
|
||||
subtask.status.toLowerCase() === statusFilter.toLowerCase()
|
||||
);
|
||||
// Return the filtered task and the original count
|
||||
return { task: filteredTask, originalSubtaskCount: originalSubtaskCount };
|
||||
|
||||
taskResult = filteredTask;
|
||||
originalSubtaskCount = originalSubtaskCount;
|
||||
}
|
||||
|
||||
// Return original task and null count if no filter or no subtasks
|
||||
return { task: task, originalSubtaskCount: null };
|
||||
// If task found and complexityReport provided, add complexity data
|
||||
if (taskResult && complexityReport) {
|
||||
addComplexityToTask(taskResult, complexityReport);
|
||||
}
|
||||
|
||||
// Return the found task and original subtask count
|
||||
return { task: taskResult, originalSubtaskCount };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,10 +562,11 @@ export {
|
||||
findCycles,
|
||||
toKebabCase,
|
||||
detectCamelCaseFlags,
|
||||
enableSilentMode,
|
||||
disableSilentMode,
|
||||
isSilentMode,
|
||||
resolveEnvVariable,
|
||||
enableSilentMode,
|
||||
getTaskManager,
|
||||
isSilentMode,
|
||||
addComplexityToTask,
|
||||
resolveEnvVariable,
|
||||
findProjectRoot
|
||||
};
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import { jest } from '@jest/globals';
|
||||
import path from 'path';
|
||||
import path, { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
// Get the current module's directory
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
@@ -27,6 +26,7 @@ const mockReadJSON = jest.fn();
|
||||
const mockWriteJSON = jest.fn();
|
||||
const mockEnableSilentMode = jest.fn();
|
||||
const mockDisableSilentMode = jest.fn();
|
||||
const mockReadComplexityReport = jest.fn().mockReturnValue(null);
|
||||
|
||||
const mockGetAnthropicClient = jest.fn().mockReturnValue({});
|
||||
const mockGetConfiguredAnthropicClient = jest.fn().mockReturnValue({});
|
||||
@@ -130,6 +130,7 @@ jest.mock('../../../scripts/modules/utils.js', () => ({
|
||||
writeJSON: mockWriteJSON,
|
||||
enableSilentMode: mockEnableSilentMode,
|
||||
disableSilentMode: mockDisableSilentMode,
|
||||
readComplexityReport: mockReadComplexityReport,
|
||||
CONFIG: {
|
||||
model: 'claude-3-7-sonnet-20250219',
|
||||
maxTokens: 64000,
|
||||
@@ -160,15 +161,6 @@ jest.mock('../../../scripts/modules/task-manager.js', () => ({
|
||||
}));
|
||||
|
||||
// Import dependencies after mocks are set up
|
||||
import fs from 'fs';
|
||||
import {
|
||||
readJSON,
|
||||
writeJSON,
|
||||
enableSilentMode,
|
||||
disableSilentMode
|
||||
} from '../../../scripts/modules/utils.js';
|
||||
import { expandTask } from '../../../scripts/modules/task-manager.js';
|
||||
import { findTasksJsonPath } from '../../../mcp-server/src/core/utils/path-utils.js';
|
||||
import { sampleTasks } from '../../fixtures/sample-tasks.js';
|
||||
|
||||
// Mock logger
|
||||
@@ -220,6 +212,37 @@ describe('MCP Server Direct Functions', () => {
|
||||
});
|
||||
|
||||
describe('listTasksDirect', () => {
|
||||
// Sample complexity report for testing
|
||||
const mockComplexityReport = {
|
||||
meta: {
|
||||
generatedAt: '2025-03-24T20:01:35.986Z',
|
||||
tasksAnalyzed: 3,
|
||||
thresholdScore: 5,
|
||||
projectName: 'Test Project',
|
||||
usedResearch: false
|
||||
},
|
||||
complexityAnalysis: [
|
||||
{
|
||||
taskId: 1,
|
||||
taskTitle: 'Initialize Project',
|
||||
complexityScore: 3,
|
||||
recommendedSubtasks: 2
|
||||
},
|
||||
{
|
||||
taskId: 2,
|
||||
taskTitle: 'Create Core Functionality',
|
||||
complexityScore: 8,
|
||||
recommendedSubtasks: 5
|
||||
},
|
||||
{
|
||||
taskId: 3,
|
||||
taskTitle: 'Implement UI Components',
|
||||
complexityScore: 6,
|
||||
recommendedSubtasks: 4
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Test wrapper function that doesn't rely on the actual implementation
|
||||
async function testListTasks(args, mockLogger) {
|
||||
// File not found case
|
||||
@@ -235,21 +258,35 @@ describe('MCP Server Direct Functions', () => {
|
||||
};
|
||||
}
|
||||
|
||||
// Check for complexity report
|
||||
const complexityReport = mockReadComplexityReport();
|
||||
let tasksData = [...sampleTasks.tasks];
|
||||
|
||||
// Add complexity scores if report exists
|
||||
if (complexityReport && complexityReport.complexityAnalysis) {
|
||||
tasksData = tasksData.map((task) => {
|
||||
const analysis = complexityReport.complexityAnalysis.find(
|
||||
(a) => a.taskId === task.id
|
||||
);
|
||||
if (analysis) {
|
||||
return { ...task, complexityScore: analysis.complexityScore };
|
||||
}
|
||||
return task;
|
||||
});
|
||||
}
|
||||
|
||||
// Success case
|
||||
if (!args.status && !args.withSubtasks) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
tasks: sampleTasks.tasks,
|
||||
tasks: tasksData,
|
||||
stats: {
|
||||
total: sampleTasks.tasks.length,
|
||||
completed: sampleTasks.tasks.filter((t) => t.status === 'done')
|
||||
total: tasksData.length,
|
||||
completed: tasksData.filter((t) => t.status === 'done').length,
|
||||
inProgress: tasksData.filter((t) => t.status === 'in-progress')
|
||||
.length,
|
||||
inProgress: sampleTasks.tasks.filter(
|
||||
(t) => t.status === 'in-progress'
|
||||
).length,
|
||||
pending: sampleTasks.tasks.filter((t) => t.status === 'pending')
|
||||
.length
|
||||
pending: tasksData.filter((t) => t.status === 'pending').length
|
||||
}
|
||||
},
|
||||
fromCache: false
|
||||
@@ -258,16 +295,14 @@ describe('MCP Server Direct Functions', () => {
|
||||
|
||||
// Status filter case
|
||||
if (args.status) {
|
||||
const filteredTasks = sampleTasks.tasks.filter(
|
||||
(t) => t.status === args.status
|
||||
);
|
||||
const filteredTasks = tasksData.filter((t) => t.status === args.status);
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
tasks: filteredTasks,
|
||||
filter: args.status,
|
||||
stats: {
|
||||
total: sampleTasks.tasks.length,
|
||||
total: tasksData.length,
|
||||
filtered: filteredTasks.length
|
||||
}
|
||||
},
|
||||
@@ -280,10 +315,10 @@ describe('MCP Server Direct Functions', () => {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
tasks: sampleTasks.tasks,
|
||||
tasks: tasksData,
|
||||
includeSubtasks: true,
|
||||
stats: {
|
||||
total: sampleTasks.tasks.length
|
||||
total: tasksData.length
|
||||
}
|
||||
},
|
||||
fromCache: false
|
||||
@@ -370,6 +405,29 @@ describe('MCP Server Direct Functions', () => {
|
||||
expect(result.error.code).toBe('FILE_NOT_FOUND_ERROR');
|
||||
expect(mockLogger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should include complexity scores when complexity report exists', async () => {
|
||||
// Arrange
|
||||
mockReadComplexityReport.mockReturnValueOnce(mockComplexityReport);
|
||||
const args = {
|
||||
projectRoot: testProjectRoot,
|
||||
file: testTasksPath,
|
||||
withSubtasks: true
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = await testListTasks(args, mockLogger);
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
|
||||
// Check that tasks have complexity scores from the report
|
||||
mockComplexityReport.complexityAnalysis.forEach((analysis) => {
|
||||
const task = result.data.tasks.find((t) => t.id === analysis.taskId);
|
||||
if (task) {
|
||||
expect(task.complexityScore).toBe(analysis.complexityScore);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('expandTaskDirect', () => {
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* Task finder tests
|
||||
*/
|
||||
|
||||
// Import after mocks are set up - No mocks needed for readComplexityReport anymore
|
||||
import { findTaskById } from '../../scripts/modules/utils.js';
|
||||
import { sampleTasks, emptySampleTasks } from '../fixtures/sample-tasks.js';
|
||||
import { emptySampleTasks, sampleTasks } from '../fixtures/sample-tasks.js';
|
||||
|
||||
describe('Task Finder', () => {
|
||||
describe('findTaskById function', () => {
|
||||
@@ -55,5 +56,62 @@ describe('Task Finder', () => {
|
||||
expect(result.task).toBeNull();
|
||||
expect(result.originalSubtaskCount).toBeNull();
|
||||
});
|
||||
test('should work correctly when no complexity report is provided', () => {
|
||||
// Pass null as the complexity report
|
||||
const result = findTaskById(sampleTasks.tasks, 2, null);
|
||||
|
||||
expect(result.task).toBeDefined();
|
||||
expect(result.task.id).toBe(2);
|
||||
expect(result.task.complexityScore).toBeUndefined();
|
||||
});
|
||||
test('should work correctly when task has no complexity data in the provided report', () => {
|
||||
// Define a complexity report that doesn't include task 2
|
||||
const complexityReport = {
|
||||
complexityAnalysis: [{ taskId: 999, complexityScore: 5 }]
|
||||
};
|
||||
|
||||
const result = findTaskById(sampleTasks.tasks, 2, complexityReport);
|
||||
|
||||
expect(result.task).toBeDefined();
|
||||
expect(result.task.id).toBe(2);
|
||||
expect(result.task.complexityScore).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should include complexity score when report is provided', () => {
|
||||
// Define the complexity report for this test
|
||||
const complexityReport = {
|
||||
meta: {
|
||||
generatedAt: '2023-01-01T00:00:00.000Z',
|
||||
tasksAnalyzed: 3,
|
||||
thresholdScore: 5
|
||||
},
|
||||
complexityAnalysis: [
|
||||
{
|
||||
taskId: 1,
|
||||
taskTitle: 'Initialize Project',
|
||||
complexityScore: 3,
|
||||
recommendedSubtasks: 2
|
||||
},
|
||||
{
|
||||
taskId: 2,
|
||||
taskTitle: 'Create Core Functionality',
|
||||
complexityScore: 8,
|
||||
recommendedSubtasks: 5
|
||||
},
|
||||
{
|
||||
taskId: 3,
|
||||
taskTitle: 'Implement UI Components',
|
||||
complexityScore: 6,
|
||||
recommendedSubtasks: 4
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const result = findTaskById(sampleTasks.tasks, 2, complexityReport);
|
||||
|
||||
expect(result.task).toBeDefined();
|
||||
expect(result.task.id).toBe(2);
|
||||
expect(result.task.complexityScore).toBe(8);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user