fix: expand_all now uses complexity analysis recommendations (#1287)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
16
.changeset/smart-owls-relax.md
Normal file
16
.changeset/smart-owls-relax.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
"task-master-ai": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.
|
||||||
|
|
||||||
|
The expand-all operation now automatically leverages recommendations from `analyze-complexity` to determine optimal subtask counts for each task, resulting in more accurate and context-aware task breakdowns.
|
||||||
|
|
||||||
|
Key improvements:
|
||||||
|
- Automatic integration with complexity analysis reports
|
||||||
|
- Tag-aware complexity report path resolution
|
||||||
|
- Intelligent subtask count determination based on task complexity
|
||||||
|
- Falls back to defaults when complexity analysis is unavailable
|
||||||
|
- Enhanced logging for better visibility into expansion decisions
|
||||||
|
|
||||||
|
When you run `task-master expand --all` after `task-master analyze-complexity`, Task Master now uses the recommended subtask counts from the complexity analysis instead of applying uniform defaults, ensuring each task is broken down according to its actual complexity.
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
disableSilentMode
|
disableSilentMode
|
||||||
} from '../../../../scripts/modules/utils.js';
|
} from '../../../../scripts/modules/utils.js';
|
||||||
import { createLogWrapper } from '../../tools/utils.js';
|
import { createLogWrapper } from '../../tools/utils.js';
|
||||||
|
import { resolveComplexityReportOutputPath } from '../../../../src/utils/path-utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand all pending tasks with subtasks (Direct Function Wrapper)
|
* Expand all pending tasks with subtasks (Direct Function Wrapper)
|
||||||
@@ -25,13 +26,30 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
*/
|
*/
|
||||||
export async function expandAllTasksDirect(args, log, context = {}) {
|
export async function expandAllTasksDirect(args, log, context = {}) {
|
||||||
const { session } = context; // Extract session
|
const { session } = context; // Extract session
|
||||||
// Destructure expected args, including projectRoot
|
// Destructure expected args, including projectRoot and complexityReportPath
|
||||||
const { tasksJsonPath, num, research, prompt, force, projectRoot, tag } =
|
const {
|
||||||
args;
|
tasksJsonPath,
|
||||||
|
num,
|
||||||
|
research,
|
||||||
|
prompt,
|
||||||
|
force,
|
||||||
|
projectRoot,
|
||||||
|
tag,
|
||||||
|
complexityReportPath: providedComplexityReportPath
|
||||||
|
} = args;
|
||||||
|
|
||||||
// Create logger wrapper using the utility
|
// Create logger wrapper using the utility
|
||||||
const mcpLog = createLogWrapper(log);
|
const mcpLog = createLogWrapper(log);
|
||||||
|
|
||||||
|
// Use provided complexity report path or compute it
|
||||||
|
const complexityReportPath =
|
||||||
|
providedComplexityReportPath ||
|
||||||
|
resolveComplexityReportOutputPath(null, { projectRoot, tag }, log);
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
`Expand all tasks will use complexity report at: ${complexityReportPath}`
|
||||||
|
);
|
||||||
|
|
||||||
if (!tasksJsonPath) {
|
if (!tasksJsonPath) {
|
||||||
log.error('expandAllTasksDirect called without tasksJsonPath');
|
log.error('expandAllTasksDirect called without tasksJsonPath');
|
||||||
return {
|
return {
|
||||||
@@ -55,14 +73,14 @@ export async function expandAllTasksDirect(args, log, context = {}) {
|
|||||||
const additionalContext = prompt || '';
|
const additionalContext = prompt || '';
|
||||||
const forceFlag = force === true;
|
const forceFlag = force === true;
|
||||||
|
|
||||||
// Call the core function, passing options and the context object { session, mcpLog, projectRoot }
|
// Call the core function, passing options and the context object { session, mcpLog, projectRoot, tag, complexityReportPath }
|
||||||
const result = await expandAllTasks(
|
const result = await expandAllTasks(
|
||||||
tasksJsonPath,
|
tasksJsonPath,
|
||||||
numSubtasks,
|
numSubtasks,
|
||||||
useResearch,
|
useResearch,
|
||||||
additionalContext,
|
additionalContext,
|
||||||
forceFlag,
|
forceFlag,
|
||||||
{ session, mcpLog, projectRoot, tag },
|
{ session, mcpLog, projectRoot, tag, complexityReportPath },
|
||||||
'json'
|
'json'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
findTasksPath as coreFindTasksPath,
|
findTasksPath as coreFindTasksPath,
|
||||||
findPRDPath as coreFindPrdPath,
|
findPRDPath as coreFindPrdPath,
|
||||||
findComplexityReportPath as coreFindComplexityReportPath,
|
findComplexityReportPath as coreFindComplexityReportPath,
|
||||||
|
resolveComplexityReportOutputPath as coreResolveComplexityReportOutputPath,
|
||||||
findProjectRoot as coreFindProjectRoot,
|
findProjectRoot as coreFindProjectRoot,
|
||||||
normalizeProjectRoot
|
normalizeProjectRoot
|
||||||
} from '../../../../src/utils/path-utils.js';
|
} from '../../../../src/utils/path-utils.js';
|
||||||
@@ -224,6 +225,21 @@ export function findComplexityReportPath(args, log = silentLogger) {
|
|||||||
return resolveComplexityReportPath(args, log);
|
return resolveComplexityReportPath(args, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve complexity report output path (create if needed) - primary MCP function
|
||||||
|
* @param {string|null} [explicitPath] - Explicit path to complexity report
|
||||||
|
* @param {Object} args - Arguments object containing projectRoot and tag
|
||||||
|
* @param {Object} [log] - Log function to prevent console logging
|
||||||
|
* @returns {string} - Resolved output path for complexity report
|
||||||
|
*/
|
||||||
|
export function resolveComplexityReportOutputPath(
|
||||||
|
explicitPath,
|
||||||
|
args,
|
||||||
|
log = silentLogger
|
||||||
|
) {
|
||||||
|
return coreResolveComplexityReportOutputPath(explicitPath, args, log);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find PRD path - primary MCP function
|
* Find PRD path - primary MCP function
|
||||||
* @param {string} [explicitPath] - Explicit path to PRD file
|
* @param {string} [explicitPath] - Explicit path to PRD file
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import {
|
|||||||
withNormalizedProjectRoot
|
withNormalizedProjectRoot
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { expandAllTasksDirect } from '../core/task-master-core.js';
|
import { expandAllTasksDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import {
|
||||||
|
findTasksPath,
|
||||||
|
resolveComplexityReportOutputPath
|
||||||
|
} from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
import { resolveTag } from '../../../scripts/modules/utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,6 +88,14 @@ export function registerExpandAllTool(server) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve complexity report path to use recommendations from analyze-complexity
|
||||||
|
const complexityReportPath = resolveComplexityReportOutputPath(
|
||||||
|
null,
|
||||||
|
{ projectRoot: args.projectRoot, tag: resolvedTag },
|
||||||
|
log
|
||||||
|
);
|
||||||
|
log.info(`Using complexity report path: ${complexityReportPath}`);
|
||||||
|
|
||||||
const result = await expandAllTasksDirect(
|
const result = await expandAllTasksDirect(
|
||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
@@ -93,7 +104,8 @@ export function registerExpandAllTool(server) {
|
|||||||
prompt: args.prompt,
|
prompt: args.prompt,
|
||||||
force: args.force,
|
force: args.force,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: resolvedTag,
|
||||||
|
complexityReportPath
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -244,6 +244,53 @@ describe('expandAllTasks', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should pass complexityReportPath to expandTask when provided in context', async () => {
|
||||||
|
// Arrange
|
||||||
|
const mockComplexityReportPath =
|
||||||
|
'/test/project/.taskmaster/reports/task-complexity-report.json';
|
||||||
|
mockExpandTask.mockResolvedValue({
|
||||||
|
telemetryData: { commandName: 'expand-task', totalCost: 0.05 }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await expandAllTasks(
|
||||||
|
mockTasksPath,
|
||||||
|
undefined, // numSubtasks not specified, should use complexity report
|
||||||
|
false,
|
||||||
|
'',
|
||||||
|
false,
|
||||||
|
{
|
||||||
|
session: mockSession,
|
||||||
|
mcpLog: mockMcpLog,
|
||||||
|
projectRoot: mockProjectRoot,
|
||||||
|
tag: 'master',
|
||||||
|
complexityReportPath: mockComplexityReportPath
|
||||||
|
},
|
||||||
|
'json'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
expect(result.expandedCount).toBe(2); // Tasks 1 and 2
|
||||||
|
|
||||||
|
// Verify expandTask was called with complexityReportPath in context
|
||||||
|
expect(mockExpandTask).toHaveBeenCalledWith(
|
||||||
|
mockTasksPath,
|
||||||
|
expect.any(Number), // task id
|
||||||
|
undefined, // numSubtasks
|
||||||
|
false, // useResearch
|
||||||
|
'', // additionalContext
|
||||||
|
expect.objectContaining({
|
||||||
|
session: mockSession,
|
||||||
|
mcpLog: mockMcpLog,
|
||||||
|
projectRoot: mockProjectRoot,
|
||||||
|
tag: 'master',
|
||||||
|
complexityReportPath: mockComplexityReportPath
|
||||||
|
}),
|
||||||
|
false // force
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('should return success with message when no tasks are eligible', async () => {
|
test('should return success with message when no tasks are eligible', async () => {
|
||||||
// Arrange - Mock tasks data with no eligible tasks
|
// Arrange - Mock tasks data with no eligible tasks
|
||||||
const noEligibleTasksData = {
|
const noEligibleTasksData = {
|
||||||
|
|||||||
Reference in New Issue
Block a user