feat: deprecate generate command

This commit is contained in:
Ralph Khreish
2025-11-17 17:45:40 +01:00
parent 3d19921ab4
commit b21a3ab1ee
40 changed files with 15 additions and 1183 deletions

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": minor
---
Deprecated generate command

View File

@@ -32,7 +32,6 @@ task-master expand --all --research # Expand all eligible tasks
task-master add-dependency --id=<id> --depends-on=<id> # Add task dependency
task-master move --from=<id> --to=<id> # Reorganize task hierarchy
task-master validate-dependencies # Check for dependency issues
task-master generate # Update task markdown files (usually auto-called)
```
## Key Files & Project Structure
@@ -361,9 +360,6 @@ task-master models --set-fallback gpt-4o-mini
### Task File Sync Issues
```bash
# Regenerate task files from tasks.json
task-master generate
# Fix dependency issues
task-master fix-dependencies
```
@@ -389,8 +385,6 @@ These commands make AI calls and may take up to a minute:
- Never manually edit `tasks.json` - use commands instead
- Never manually edit `.taskmaster/config.json` - use `task-master models`
- Task markdown files in `tasks/` are auto-generated
- Run `task-master generate` after manual changes to tasks.json
### Claude Code Session Management

View File

@@ -277,9 +277,6 @@ task-master move --from=5 --from-tag=backlog --to-tag=in-progress
task-master move --from=5,6,7 --from-tag=backlog --to-tag=done --with-dependencies
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies
# Generate task files
task-master generate
# Add rules after initialization
task-master rules add windsurf,roo,vscode
```

View File

@@ -103,13 +103,6 @@ task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>" --resea
Unlike the `update-task` command which replaces task information, the `update-subtask` command _appends_ new information to the existing subtask details, marking it with a timestamp. This is useful for iteratively enhancing subtasks while preserving the original content.
## Generate Task Files
```bash
# Generate individual task files from tasks.json
task-master generate
```
## Set Task Status
```bash

View File

@@ -107,9 +107,6 @@ task-master list
# Show the next task to work on
task-master next
# Generate task files
task-master generate
```
## Setting up Cursor AI Integration
@@ -178,14 +175,6 @@ Next, ask the agent to generate individual task files:
Please generate individual task files from tasks.json
```
The agent will execute:
```bash
task-master generate
```
This creates individual task files in the `tasks/` directory (e.g., `task_001.txt`, `task_002.txt`), making it easier to reference specific tasks.
## AI-Driven Development Workflow
The Cursor agent is pre-configured (via the rules file) to follow this workflow:

View File

@@ -1,102 +0,0 @@
/**
* generate-task-files.js
* Direct function implementation for generating task files from tasks.json
*/
import { generateTaskFiles } from '../../../../scripts/modules/task-manager.js';
import {
enableSilentMode,
disableSilentMode
} from '../../../../scripts/modules/utils.js';
/**
* Direct function wrapper for generateTaskFiles with error handling.
*
* @param {Object} args - Command arguments containing tasksJsonPath and outputDir.
* @param {string} args.tasksJsonPath - Path to the tasks.json file.
* @param {string} args.outputDir - Path to the output directory.
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
* @param {string} args.tag - Tag for the task (optional)
* @param {Object} log - Logger object.
* @returns {Promise<Object>} - Result object with success status and data/error information.
*/
export async function generateTaskFilesDirect(args, log) {
// Destructure expected args
const { tasksJsonPath, outputDir, projectRoot, tag } = args;
try {
log.info(`Generating task files with args: ${JSON.stringify(args)}`);
// Check if paths were provided
if (!tasksJsonPath) {
const errorMessage = 'tasksJsonPath is required but was not provided.';
log.error(errorMessage);
return {
success: false,
error: { code: 'MISSING_ARGUMENT', message: errorMessage }
};
}
if (!outputDir) {
const errorMessage = 'outputDir is required but was not provided.';
log.error(errorMessage);
return {
success: false,
error: { code: 'MISSING_ARGUMENT', message: errorMessage }
};
}
// Use the provided paths
const tasksPath = tasksJsonPath;
const resolvedOutputDir = outputDir;
log.info(`Generating task files from ${tasksPath} to ${resolvedOutputDir}`);
// Execute core generateTaskFiles function in a separate try/catch
try {
// Enable silent mode to prevent logs from being written to stdout
enableSilentMode();
// Pass projectRoot and tag so the core respects context
generateTaskFiles(tasksPath, resolvedOutputDir, {
projectRoot,
tag,
mcpLog: log
});
// Restore normal logging after task generation
disableSilentMode();
} catch (genError) {
// Make sure to restore normal logging even if there's an error
disableSilentMode();
log.error(`Error in generateTaskFiles: ${genError.message}`);
return {
success: false,
error: { code: 'GENERATE_FILES_ERROR', message: genError.message }
};
}
// Return success with file paths
return {
success: true,
data: {
message: `Successfully generated task files`,
tasksPath: tasksPath,
outputDir: resolvedOutputDir,
taskFiles:
'Individual task files have been generated in the output directory'
}
};
} catch (error) {
// Make sure to restore normal logging if an outer error occurs
disableSilentMode();
log.error(`Error generating task files: ${error.message}`);
return {
success: false,
error: {
code: 'GENERATE_TASKS_ERROR',
message: error.message || 'Unknown error generating task files'
}
};
}
}

View File

@@ -10,7 +10,6 @@ import { parsePRDDirect } from './direct-functions/parse-prd.js';
import { updateTasksDirect } from './direct-functions/update-tasks.js';
import { updateTaskByIdDirect } from './direct-functions/update-task-by-id.js';
import { updateSubtaskByIdDirect } from './direct-functions/update-subtask-by-id.js';
import { generateTaskFilesDirect } from './direct-functions/generate-task-files.js';
import { setTaskStatusDirect } from './direct-functions/set-task-status.js';
import { nextTaskDirect } from './direct-functions/next-task.js';
import { expandTaskDirect } from './direct-functions/expand-task.js';
@@ -50,7 +49,6 @@ export const directFunctions = new Map([
['updateTasksDirect', updateTasksDirect],
['updateTaskByIdDirect', updateTaskByIdDirect],
['updateSubtaskByIdDirect', updateSubtaskByIdDirect],
['generateTaskFilesDirect', generateTaskFilesDirect],
['setTaskStatusDirect', setTaskStatusDirect],
['nextTaskDirect', nextTaskDirect],
['expandTaskDirect', expandTaskDirect],
@@ -88,7 +86,6 @@ export {
updateTasksDirect,
updateTaskByIdDirect,
updateSubtaskByIdDirect,
generateTaskFilesDirect,
setTaskStatusDirect,
nextTaskDirect,
expandTaskDirect,

View File

@@ -1,95 +0,0 @@
/**
* tools/generate.js
* Tool to generate individual task files from tasks.json
*/
import { z } from 'zod';
import {
handleApiResult,
createErrorResponse,
withNormalizedProjectRoot
} from './utils.js';
import { generateTaskFilesDirect } from '../core/task-master-core.js';
import { findTasksPath } from '../core/utils/path-utils.js';
import { resolveTag } from '../../../scripts/modules/utils.js';
import path from 'path';
/**
* Register the generate tool with the MCP server
* @param {Object} server - FastMCP server instance
*/
export function registerGenerateTool(server) {
server.addTool({
name: 'generate',
description:
'Generates individual task files in tasks/ directory based on tasks.json',
parameters: z.object({
file: z.string().optional().describe('Absolute path to the tasks file'),
output: z
.string()
.optional()
.describe('Output directory (default: same directory as tasks file)'),
projectRoot: z
.string()
.describe('The directory of the project. Must be an absolute path.'),
tag: z.string().optional().describe('Tag context to operate on')
}),
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
try {
log.info(`Generating task files with args: ${JSON.stringify(args)}`);
const resolvedTag = resolveTag({
projectRoot: args.projectRoot,
tag: args.tag
});
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
let tasksJsonPath;
try {
tasksJsonPath = findTasksPath(
{ projectRoot: args.projectRoot, file: args.file },
log
);
} catch (error) {
log.error(`Error finding tasks.json: ${error.message}`);
return createErrorResponse(
`Failed to find tasks.json: ${error.message}`
);
}
const outputDir = args.output
? path.resolve(args.projectRoot, args.output)
: path.dirname(tasksJsonPath);
const result = await generateTaskFilesDirect(
{
tasksJsonPath: tasksJsonPath,
outputDir: outputDir,
projectRoot: args.projectRoot,
tag: resolvedTag
},
log,
{ session }
);
if (result.success) {
log.info(`Successfully generated task files: ${result.data.message}`);
} else {
log.error(
`Failed to generate task files: ${result.error?.message || 'Unknown error'}`
);
}
return handleApiResult(
result,
log,
'Error generating task files',
undefined,
args.projectRoot
);
} catch (error) {
log.error(`Error in generate tool: ${error.message}`);
return createErrorResponse(error.message);
}
})
});
}

View File

@@ -8,7 +8,6 @@ import { registerParsePRDTool } from './parse-prd.js';
import { registerUpdateTool } from './update.js';
import { registerUpdateTaskTool } from './update-task.js';
import { registerUpdateSubtaskTool } from './update-subtask.js';
import { registerGenerateTool } from './generate.js';
import { registerNextTaskTool } from './next-task.js';
import { registerExpandTaskTool } from './expand-task.js';
import { registerAddTaskTool } from './add-task.js';
@@ -72,7 +71,6 @@ export const toolRegistry = {
next_task: registerNextTaskTool,
complexity_report: registerComplexityReportTool,
set_task_status: registerSetTaskStatusTool,
generate: registerGenerateTool,
add_task: registerAddTaskTool,
add_subtask: registerAddSubtaskTool,
update: registerUpdateTool,
@@ -128,7 +126,6 @@ export const standardTools = [
'expand_all',
'add_subtask',
'remove_task',
'generate',
'add_task',
'complexity_report'
];

View File

@@ -1,121 +0,0 @@
Generate individual task files from tasks.json.
## Task File Generation
Creates separate markdown files for each task, perfect for AI agents or documentation.
## Execution
```bash
task-master generate
```
## What It Creates
For each task, generates a file like `task_001.txt`:
```
Task ID: 1
Title: Implement user authentication
Status: pending
Priority: high
Dependencies: []
Created: 2024-01-15
Complexity: 7
## Description
Create a secure user authentication system with login, logout, and session management.
## Details
- Use JWT tokens for session management
- Implement secure password hashing
- Add remember me functionality
- Include password reset flow
## Test Strategy
- Unit tests for auth functions
- Integration tests for login flow
- Security testing for vulnerabilities
- Performance tests for concurrent logins
## Subtasks
1.1 Setup authentication framework (pending)
1.2 Create login endpoints (pending)
1.3 Implement session management (pending)
1.4 Add password reset (pending)
```
## File Organization
Creates structure:
```
.taskmaster/
└── tasks/
├── task_001.txt
├── task_002.txt
├── task_003.txt
└── ...
```
## Smart Features
1. **Consistent Formatting**
- Standardized structure
- Clear sections
- AI-readable format
- Markdown compatible
2. **Contextual Information**
- Full task details
- Related task references
- Progress indicators
- Implementation notes
3. **Incremental Updates**
- Only regenerate changed tasks
- Preserve custom additions
- Track generation timestamp
- Version control friendly
## Use Cases
- **AI Context**: Provide task context to AI assistants
- **Documentation**: Standalone task documentation
- **Archival**: Task history preservation
- **Sharing**: Send specific tasks to team members
- **Review**: Easier task review process
## Generation Options
Based on arguments:
- Filter by status
- Include/exclude completed
- Custom templates
- Different formats
## Post-Generation
```
Task File Generation Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━
Generated: 45 task files
Location: .taskmaster/tasks/
Total size: 156 KB
New files: 5
Updated files: 12
Unchanged: 28
Ready for:
- AI agent consumption
- Version control
- Team distribution
```
## Integration Benefits
- Git-trackable task history
- Easy task sharing
- AI tool compatibility
- Offline task access
- Backup redundancy

View File

@@ -25,7 +25,6 @@ import {
import {
parsePRD,
updateTasks,
generateTaskFiles,
expandTask,
expandAllTasks,
clearSubtasks,
@@ -1000,42 +999,6 @@ function registerCommands(programInstance) {
}
});
// generate command
programInstance
.command('generate')
.description('Generate task files from tasks.json')
.option(
'-f, --file <file>',
'Path to the tasks file',
TASKMASTER_TASKS_FILE
)
.option(
'-o, --output <dir>',
'Output directory',
path.dirname(TASKMASTER_TASKS_FILE)
)
.option('--tag <tag>', 'Specify tag context for task operations')
.action(async (options) => {
// Initialize TaskMaster
const taskMaster = initTaskMaster({
tasksPath: options.file || true,
tag: options.tag
});
const outputDir = options.output;
const tag = taskMaster.getCurrentTag();
console.log(
chalk.blue(`Generating task files from: ${taskMaster.getTasksPath()}`)
);
console.log(chalk.blue(`Output directory: ${outputDir}`));
await generateTaskFiles(taskMaster.getTasksPath(), outputDir, {
projectRoot: taskMaster.getProjectRoot(),
tag
});
});
// ========================================
// Register All Commands from @tm/cli
// ========================================
@@ -3340,33 +3303,6 @@ Examples:
console.log('\n' + chalk.yellow.bold('Next Steps:'));
result.tips.forEach((t) => console.log(chalk.white(`${t}`)));
}
// Check if source tag still contains tasks before regenerating files
const tasksData = readJSON(
taskMaster.getTasksPath(),
taskMaster.getProjectRoot(),
sourceTag
);
const sourceTagHasTasks =
tasksData &&
Array.isArray(tasksData.tasks) &&
tasksData.tasks.length > 0;
// Generate task files for the affected tags
await generateTaskFiles(
taskMaster.getTasksPath(),
path.dirname(taskMaster.getTasksPath()),
{ tag: toTag, projectRoot: taskMaster.getProjectRoot() }
);
// Only regenerate source tag files if it still contains tasks
if (sourceTagHasTasks) {
await generateTaskFiles(
taskMaster.getTasksPath(),
path.dirname(taskMaster.getTasksPath()),
{ tag: sourceTag, projectRoot: taskMaster.getProjectRoot() }
);
}
}
// Helper function to handle within-tag move logic

View File

@@ -20,8 +20,6 @@ import {
import { displayBanner } from './ui.js';
import generateTaskFiles from './task-manager/generate-task-files.js';
/**
* Structured error class for dependency operations
*/

View File

@@ -7,7 +7,6 @@ import { findTaskById } from './utils.js';
import parsePRD from './task-manager/parse-prd/index.js';
import updateTasks from './task-manager/update-tasks.js';
import updateTaskById from './task-manager/update-task-by-id.js';
import generateTaskFiles from './task-manager/generate-task-files.js';
import setTaskStatus from './task-manager/set-task-status.js';
import updateSingleTaskStatus from './task-manager/update-single-task-status.js';
import listTasks from './task-manager/list-tasks.js';
@@ -40,7 +39,6 @@ export {
updateTasks,
updateTaskById,
updateSubtaskById,
generateTaskFiles,
setTaskStatus,
updateSingleTaskStatus,
listTasks,

View File

@@ -27,7 +27,6 @@ import { generateObjectService } from '../ai-services-unified.js';
import { getDefaultPriority, hasCodebaseAnalysis } from '../config-manager.js';
import { getPromptManager } from '../prompt-manager.js';
import ContextGatherer from '../utils/contextGatherer.js';
import generateTaskFiles from './generate-task-files.js';
import { COMMAND_SCHEMAS } from '../../../src/schemas/registry.js';
import {
TASK_PRIORITY_OPTIONS,

View File

@@ -1,202 +0,0 @@
import path from 'path';
import fs from 'fs';
import chalk from 'chalk';
import { log, readJSON } from '../utils.js';
import { formatDependenciesWithStatus } from '../ui.js';
import { validateAndFixDependencies } from '../dependency-manager.js';
import { getDebugFlag } from '../config-manager.js';
/**
* Generate individual task files from tasks.json
* @param {string} tasksPath - Path to the tasks.json file
* @param {string} outputDir - Output directory for task files
* @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot, tag)
* @param {string} [options.projectRoot] - Project root path
* @param {string} [options.tag] - Tag for the task
* @param {Object} [options.mcpLog] - MCP logger object
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
*/
function generateTaskFiles(tasksPath, outputDir, options = {}) {
try {
const isMcpMode = !!options?.mcpLog;
const { projectRoot, tag } = options;
// 1. Read the raw data structure, ensuring we have all tags.
// We call readJSON without a specific tag to get the resolved default view,
// which correctly contains the full structure in `_rawTaggedData`.
const resolvedData = readJSON(tasksPath, projectRoot, tag);
if (!resolvedData) {
throw new Error(`Could not read or parse tasks file: ${tasksPath}`);
}
// Prioritize the _rawTaggedData if it exists, otherwise use the data as is.
const rawData = resolvedData._rawTaggedData || resolvedData;
// 2. Determine the target tag we need to generate files for.
const tagData = rawData[tag];
if (!tagData || !tagData.tasks) {
throw new Error(`Tag '${tag}' not found or has no tasks in the data.`);
}
const tasksForGeneration = tagData.tasks;
// Create the output directory if it doesn't exist
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
log(
'info',
`Preparing to regenerate ${tasksForGeneration.length} task files for tag '${tag}'`
);
// 3. Validate dependencies using the FULL, raw data structure to prevent data loss.
validateAndFixDependencies(
rawData, // Pass the entire object with all tags
tasksPath,
projectRoot,
tag // Provide the current tag context for the operation
);
const allTasksInTag = tagData.tasks;
const validTaskIds = allTasksInTag.map((task) => task.id);
// Cleanup orphaned task files
log('info', 'Checking for orphaned task files to clean up...');
try {
const files = fs.readdirSync(outputDir);
// Tag-aware file patterns: master -> task_001.txt, other tags -> task_001_tagname.txt
const masterFilePattern = /^task_(\d+)\.txt$/;
const taggedFilePattern = new RegExp(`^task_(\\d+)_${tag}\\.txt$`);
const orphanedFiles = files.filter((file) => {
let match = null;
let fileTaskId = null;
// Check if file belongs to current tag
if (tag === 'master') {
match = file.match(masterFilePattern);
if (match) {
fileTaskId = parseInt(match[1], 10);
// Only clean up master files when processing master tag
return !validTaskIds.includes(fileTaskId);
}
} else {
match = file.match(taggedFilePattern);
if (match) {
fileTaskId = parseInt(match[1], 10);
// Only clean up files for the current tag
return !validTaskIds.includes(fileTaskId);
}
}
return false;
});
if (orphanedFiles.length > 0) {
log(
'info',
`Found ${orphanedFiles.length} orphaned task files to remove for tag '${tag}'`
);
orphanedFiles.forEach((file) => {
const filePath = path.join(outputDir, file);
fs.unlinkSync(filePath);
});
} else {
log('info', 'No orphaned task files found.');
}
} catch (err) {
log('warn', `Error cleaning up orphaned task files: ${err.message}`);
}
// Generate task files for the target tag
log('info', `Generating individual task files for tag '${tag}'...`);
tasksForGeneration.forEach((task) => {
// Tag-aware file naming: master -> task_001.txt, other tags -> task_001_tagname.txt
const taskFileName =
tag === 'master'
? `task_${task.id.toString().padStart(3, '0')}.txt`
: `task_${task.id.toString().padStart(3, '0')}_${tag}.txt`;
const taskPath = path.join(outputDir, taskFileName);
let content = `# Task ID: ${task.id}\n`;
content += `# Title: ${task.title}\n`;
content += `# Status: ${task.status || 'pending'}\n`;
if (task.dependencies && task.dependencies.length > 0) {
content += `# Dependencies: ${formatDependenciesWithStatus(task.dependencies, allTasksInTag, false)}\n`;
} else {
content += '# Dependencies: None\n';
}
content += `# Priority: ${task.priority || 'medium'}\n`;
content += `# Description: ${task.description || ''}\n`;
content += '# Details:\n';
content += (task.details || '')
.split('\n')
.map((line) => line)
.join('\n');
content += '\n\n';
content += '# Test Strategy:\n';
content += (task.testStrategy || '')
.split('\n')
.map((line) => line)
.join('\n');
content += '\n';
if (task.subtasks && task.subtasks.length > 0) {
content += '\n# Subtasks:\n';
task.subtasks.forEach((subtask) => {
content += `## ${subtask.id}. ${subtask.title} [${subtask.status || 'pending'}]\n`;
if (subtask.dependencies && subtask.dependencies.length > 0) {
const subtaskDeps = subtask.dependencies
.map((depId) =>
typeof depId === 'number'
? `${task.id}.${depId}`
: depId.toString()
)
.join(', ');
content += `### Dependencies: ${subtaskDeps}\n`;
} else {
content += '### Dependencies: None\n';
}
content += `### Description: ${subtask.description || ''}\n`;
content += '### Details:\n';
content += (subtask.details || '')
.split('\n')
.map((line) => line)
.join('\n');
content += '\n\n';
});
}
fs.writeFileSync(taskPath, content);
});
log(
'success',
`All ${tasksForGeneration.length} tasks for tag '${tag}' have been generated into '${outputDir}'.`
);
if (isMcpMode) {
return {
success: true,
count: tasksForGeneration.length,
directory: outputDir
};
}
} catch (error) {
log('error', `Error generating task files: ${error.message}`);
if (!options?.mcpLog) {
console.error(chalk.red(`Error generating task files: ${error.message}`));
if (getDebugFlag()) {
console.error(error);
}
process.exit(1);
} else {
throw error;
}
}
}
export default generateTaskFiles;

View File

@@ -1,7 +1,6 @@
import path from 'path';
import * as fs from 'fs';
import { readJSON, writeJSON, log, findTaskById } from '../utils.js';
import generateTaskFiles from './generate-task-files.js';
import taskExists from './task-exists.js';
/**

View File

@@ -13,7 +13,6 @@ import { displayBanner } from '../ui.js';
import { validateTaskDependencies } from '../dependency-manager.js';
import { getDebugFlag } from '../config-manager.js';
import updateSingleTaskStatus from './update-single-task-status.js';
import generateTaskFiles from './generate-task-files.js';
import {
isValidTaskStatus,
TASK_STATUS_OPTIONS

View File

@@ -22,7 +22,6 @@ import {
import { generateTextService } from '../ai-services-unified.js';
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
import { getPromptManager } from '../prompt-manager.js';
import generateTaskFiles from './generate-task-files.js';
import { ContextGatherer } from '../utils/contextGatherer.js';
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
import { tryUpdateViaRemote } from '@tm/bridge';

View File

@@ -20,7 +20,6 @@ import {
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
import { getPromptManager } from '../prompt-manager.js';
import generateTaskFiles from './generate-task-files.js';
import { generateObjectService } from '../ai-services-unified.js';
import { COMMAND_SCHEMAS } from '../../../src/schemas/registry.js';
import { getModelConfiguration } from './models.js';

View File

@@ -4,8 +4,8 @@
*/
import {
getToolCounts,
getToolCategories
getToolCategories,
getToolCounts
} from '../../mcp-server/src/tools/tool-registry.js';
/**
@@ -14,8 +14,8 @@ import {
*/
export const EXPECTED_TOOL_COUNTS = {
core: 7,
standard: 15,
total: 44
standard: 14,
total: 43
};
/**

View File

@@ -1,11 +1,10 @@
import { jest } from '@jest/globals';
import fs from 'fs';
import path from 'path';
import { jest } from '@jest/globals';
// --- Define mock functions ---
const mockMoveTasksBetweenTags = jest.fn();
const mockMoveTask = jest.fn();
const mockGenerateTaskFiles = jest.fn();
const mockLog = jest.fn();
// --- Setup mocks using unstable_mockModule ---
@@ -17,13 +16,6 @@ jest.unstable_mockModule(
})
);
jest.unstable_mockModule(
'../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: mockGenerateTaskFiles
})
);
jest.unstable_mockModule('../../../scripts/modules/utils.js', () => ({
log: mockLog,
readJSON: jest.fn(),
@@ -58,7 +50,7 @@ jest.unstable_mockModule('chalk', () => ({
}));
// --- Import modules (AFTER mock setup) ---
let moveTaskModule, generateTaskFilesModule, utilsModule, chalk;
let moveTaskModule, utilsModule, chalk;
describe('Cross-Tag Move CLI Integration', () => {
// Setup dynamic imports before tests run
@@ -66,9 +58,6 @@ describe('Cross-Tag Move CLI Integration', () => {
moveTaskModule = await import(
'../../../scripts/modules/task-manager/move-task.js'
);
generateTaskFilesModule = await import(
'../../../scripts/modules/task-manager/generate-task-files.js'
);
utilsModule = await import('../../../scripts/modules/utils.js');
chalk = (await import('chalk')).default;
});
@@ -176,18 +165,6 @@ describe('Cross-Tag Move CLI Integration', () => {
console.log('Next Steps:');
result.tips.forEach((t) => console.log(`${t}`));
}
// Generate task files for both tags
await generateTaskFilesModule.default(
tasksPath,
path.dirname(tasksPath),
{ tag: sourceTag }
);
await generateTaskFilesModule.default(
tasksPath,
path.dirname(tasksPath),
{ tag: toTag }
);
} catch (error) {
console.error(chalk.red(`Error: ${error.message}`));
// Print ID collision guidance similar to CLI help block
@@ -271,7 +248,6 @@ describe('Cross-Tag Move CLI Integration', () => {
it('should move task without dependencies successfully', async () => {
// Mock successful cross-tag move
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
mockGenerateTaskFiles.mockResolvedValue(undefined);
const options = {
from: '2',
@@ -324,7 +300,6 @@ describe('Cross-Tag Move CLI Integration', () => {
it('should move task with dependencies when --with-dependencies is used', async () => {
// Mock successful cross-tag move with dependencies
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
mockGenerateTaskFiles.mockResolvedValue(undefined);
const options = {
from: '1',
@@ -350,7 +325,6 @@ describe('Cross-Tag Move CLI Integration', () => {
it('should break dependencies when --ignore-dependencies is used', async () => {
// Mock successful cross-tag move with dependency breaking
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
mockGenerateTaskFiles.mockResolvedValue(undefined);
const options = {
from: '1',
@@ -376,7 +350,6 @@ describe('Cross-Tag Move CLI Integration', () => {
it('should create target tag if it does not exist', async () => {
// Mock successful cross-tag move to new tag
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
mockGenerateTaskFiles.mockResolvedValue(undefined);
const options = {
from: '2',
@@ -567,24 +540,11 @@ describe('Cross-Tag Move CLI Integration', () => {
ignoreDependencies: false
}
);
// Verify that generateTaskFiles was called for both tags
expect(generateTaskFilesModule.default).toHaveBeenCalledWith(
expect.stringContaining('.taskmaster/tasks/tasks.json'),
expect.stringContaining('.taskmaster/tasks'),
{ tag: 'master' }
);
expect(generateTaskFilesModule.default).toHaveBeenCalledWith(
expect.stringContaining('.taskmaster/tasks/tasks.json'),
expect.stringContaining('.taskmaster/tasks'),
{ tag: 'in-progress' }
);
});
it('should move multiple tasks with comma-separated IDs successfully', async () => {
// Mock successful cross-tag move for multiple tasks
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
mockGenerateTaskFiles.mockResolvedValue(undefined);
const options = {
from: '1,2,3',
@@ -604,19 +564,6 @@ describe('Cross-Tag Move CLI Integration', () => {
ignoreDependencies: undefined
}
);
// Verify task files are generated for both tags
expect(mockGenerateTaskFiles).toHaveBeenCalledTimes(2);
expect(mockGenerateTaskFiles).toHaveBeenCalledWith(
expect.stringContaining('tasks.json'),
expect.stringContaining('.taskmaster/tasks'),
{ tag: 'backlog' }
);
expect(mockGenerateTaskFiles).toHaveBeenCalledWith(
expect.stringContaining('tasks.json'),
expect.stringContaining('.taskmaster/tasks'),
{ tag: 'in-progress' }
);
});
// Note: --force flag is no longer supported for cross-tag moves
@@ -710,7 +657,6 @@ describe('Cross-Tag Move CLI Integration', () => {
it('should handle whitespace in comma-separated task IDs', async () => {
// Mock successful cross-tag move with whitespace
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
mockGenerateTaskFiles.mockResolvedValue(undefined);
const options = {
from: ' 1 , 2 , 3 ', // Whitespace around IDs and commas

View File

@@ -111,7 +111,6 @@ const mockExpandTask = jest
}
);
const mockGenerateTaskFiles = jest.fn().mockResolvedValue(true);
const mockFindTaskById = jest.fn();
const mockTaskExists = jest.fn().mockReturnValue(true);
@@ -155,7 +154,6 @@ jest.mock('../../../scripts/modules/ai-services-unified.js', () => ({
// Mock task-manager.js to avoid real operations
jest.mock('../../../scripts/modules/task-manager.js', () => ({
expandTask: mockExpandTask,
generateTaskFiles: mockGenerateTaskFiles,
findTaskById: mockFindTaskById,
taskExists: mockTaskExists
}));

View File

@@ -1,7 +1,7 @@
import { jest } from '@jest/globals';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { jest } from '@jest/globals';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@@ -106,13 +106,6 @@ jest.unstable_mockModule('../../scripts/modules/dependency-manager.js', () => ({
})
}));
jest.unstable_mockModule(
'../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
// Import the modules we'll be testing after mocking
const { moveTasksBetweenTags } = await import(
'../../scripts/modules/task-manager/move-task.js'

View File

@@ -71,10 +71,6 @@ jest.mock('../../scripts/modules/ui.js', () => ({
displayBanner: jest.fn()
}));
jest.mock('../../scripts/modules/task-manager.js', () => ({
generateTaskFiles: jest.fn()
}));
// Use a temporary path for test files - Jest will clean up the temp directory
const TEST_TASKS_PATH = '/tmp/jest-test-tasks.json';
@@ -991,10 +987,6 @@ describe('Dependency Manager Module', () => {
await jest.unstable_mockModule('../../scripts/modules/ui.js', () => ({
displayBanner: jest.fn()
}));
await jest.unstable_mockModule(
'../../scripts/modules/task-manager/generate-task-files.js',
() => ({ default: jest.fn() })
);
// Set up test data that matches the issue report
// Clone fixture data before each test to prevent mutation issues
mockReadJSON.mockImplementation(() =>

View File

@@ -121,14 +121,6 @@ jest.unstable_mockModule('../../scripts/modules/ui.js', () => ({
displayAiUsageSummary: jest.fn()
}));
// Mock task generation to prevent file operations
jest.unstable_mockModule(
'../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn()
})
);
// Mock stream parser
jest.unstable_mockModule('../../src/utils/stream-parser.js', () => {
// Define mock StreamingError class

View File

@@ -12,7 +12,6 @@ const mockConfig = {
// Core functionality mocks (always needed)
core: {
moveTasksBetweenTags: true,
generateTaskFiles: true,
readJSON: true,
initTaskMaster: true,
findProjectRoot: true
@@ -48,9 +47,6 @@ function createMockFactory(config = mockConfig) {
if (config.core?.moveTasksBetweenTags) {
mocks.moveTasksBetweenTags = createMock('moveTasksBetweenTags');
}
if (config.core?.generateTaskFiles) {
mocks.generateTaskFiles = createMock('generateTaskFiles');
}
if (config.core?.readJSON) {
mocks.readJSON = createMock('readJSON');
}
@@ -80,14 +76,9 @@ function setupMocks(config = mockConfig) {
);
}
if (
config.core?.generateTaskFiles ||
config.core?.readJSON ||
config.core?.findProjectRoot
) {
if (config.core?.readJSON || config.core?.findProjectRoot) {
jest.mock('../../../../../scripts/modules/utils.js', () => ({
findProjectRoot: mocks.findProjectRoot,
generateTaskFiles: mocks.generateTaskFiles,
readJSON: mocks.readJSON,
// Minimal set of utils that might be used
log: jest.fn(),
@@ -172,20 +163,6 @@ async function handleCrossTagMove(moveContext, options) {
const sourceTagHasTasks =
tasksData && Array.isArray(tasksData.tasks) && tasksData.tasks.length > 0;
// Generate task files for the affected tags
await mocks.generateTaskFiles(taskMaster.getTasksPath(), 'tasks', {
tag: toTag,
projectRoot: taskMaster.getProjectRoot()
});
// Only regenerate source tag files if it still contains tasks
if (sourceTagHasTasks) {
await mocks.generateTaskFiles(taskMaster.getTasksPath(), 'tasks', {
tag: sourceTag,
projectRoot: taskMaster.getProjectRoot()
});
}
return result;
}
@@ -216,7 +193,6 @@ describe('CLI Move Command Cross-Tag Functionality', () => {
mocks.initTaskMaster.mockReturnValue(mockTaskMaster);
mocks.findProjectRoot.mockReturnValue('/test/project');
mocks.generateTaskFiles.mockResolvedValue();
mocks.readJSON.mockReturnValue({
tasks: [
{ id: 1, title: 'Test Task 1' },
@@ -482,14 +458,12 @@ describe('CLI Move Command Cross-Tag Functionality', () => {
const minimalConfig = {
core: {
moveTasksBetweenTags: true,
generateTaskFiles: true,
readJSON: true
}
};
const minimalMocks = createMockFactory(minimalConfig);
expect(minimalMocks.moveTasksBetweenTags).toBeDefined();
expect(minimalMocks.generateTaskFiles).toBeDefined();
expect(minimalMocks.readJSON).toBeDefined();
});
@@ -498,15 +472,13 @@ describe('CLI Move Command Cross-Tag Functionality', () => {
const selectiveConfig = {
core: {
moveTasksBetweenTags: true,
generateTaskFiles: false, // Disabled
readJSON: true
readJSON: false // Disabled
}
};
const selectiveMocks = createMockFactory(selectiveConfig);
expect(selectiveMocks.moveTasksBetweenTags).toBeDefined();
expect(selectiveMocks.generateTaskFiles).toBeUndefined();
expect(selectiveMocks.readJSON).toBeDefined();
expect(selectiveMocks.readJSON).toBeUndefined();
});
});
});

View File

@@ -44,13 +44,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
}));
// Mock task-manager.js
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager.js',
() => ({
generateTaskFiles: jest.fn()
})
);
// Mock external libraries
jest.unstable_mockModule('chalk', () => ({
default: {

View File

@@ -23,12 +23,6 @@ jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager.js',
() => mockTaskManager
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: mockGenerateTaskFiles
})
);
const addSubtask = (
await import('../../../../../scripts/modules/task-manager/add-subtask.js')

View File

@@ -118,13 +118,6 @@ jest.unstable_mockModule(
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/prompt-manager.js',
() => ({
@@ -173,12 +166,6 @@ const { generateObjectService } = await import(
'../../../../../scripts/modules/ai-services-unified.js'
);
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
// Import the module under test
const { default: addTask } = await import(
'../../../../../scripts/modules/task-manager/add-task.js'

View File

@@ -24,13 +24,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
displayBanner: jest.fn()
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
// Mock external UI libraries
jest.unstable_mockModule('chalk', () => ({
default: {
@@ -68,11 +61,6 @@ const mockExit = jest.spyOn(process, 'exit').mockImplementation((code) => {
// Import the mocked modules
const { readJSON, writeJSON, log, findTaskById, ensureTagMetadata } =
await import('../../../../../scripts/modules/utils.js');
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
// Import the module under test
const { default: clearSubtasks } = await import(
@@ -116,7 +104,6 @@ describe('clearSubtasks', () => {
};
});
writeJSON.mockResolvedValue();
generateTaskFiles.mockResolvedValue();
log.mockImplementation(() => {});
});
@@ -191,7 +178,6 @@ describe('clearSubtasks', () => {
expect(readJSON).toHaveBeenCalledWith(tasksPath, undefined, 'master');
// Should not write the file if no changes were made
expect(writeJSON).not.toHaveBeenCalled();
expect(generateTaskFiles).not.toHaveBeenCalled();
});
test('should handle non-existent task IDs gracefully', () => {
@@ -208,7 +194,6 @@ describe('clearSubtasks', () => {
expect(log).toHaveBeenCalledWith('error', 'Task 99 not found');
// Should not write the file if no changes were made
expect(writeJSON).not.toHaveBeenCalled();
expect(generateTaskFiles).not.toHaveBeenCalled();
});
test('should handle multiple task IDs including both valid and non-existent IDs', () => {

View File

@@ -153,13 +153,6 @@ jest.unstable_mockModule(
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/prompt-manager.js',
() => ({
@@ -246,12 +239,6 @@ const { generateObjectService } = await import(
'../../../../../scripts/modules/ai-services-unified.js'
);
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
const { getDefaultSubtasks } = await import(
'../../../../../scripts/modules/config-manager.js'
);
@@ -365,7 +352,6 @@ describe('expandTask', () => {
findProjectRoot.mockReturnValue('/mock/project/root');
writeJSON.mockResolvedValue();
generateTaskFiles.mockResolvedValue();
log.mockImplementation(() => {});
// Mock console.log to avoid output during tests

View File

@@ -1,306 +0,0 @@
/**
* Tests for the generate-task-files.js module
*/
import { jest } from '@jest/globals';
// Mock the dependencies before importing the module under test
jest.unstable_mockModule('fs', () => ({
default: {
existsSync: jest.fn(),
mkdirSync: jest.fn(),
readdirSync: jest.fn(),
unlinkSync: jest.fn(),
writeFileSync: jest.fn()
},
existsSync: jest.fn(),
mkdirSync: jest.fn(),
readdirSync: jest.fn(),
unlinkSync: jest.fn(),
writeFileSync: jest.fn()
}));
jest.unstable_mockModule('path', () => ({
default: {
join: jest.fn((...args) => args.join('/')),
dirname: jest.fn((p) => p.split('/').slice(0, -1).join('/'))
},
join: jest.fn((...args) => args.join('/')),
dirname: jest.fn((p) => p.split('/').slice(0, -1).join('/'))
}));
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
readJSON: jest.fn(),
writeJSON: jest.fn(),
log: jest.fn(),
CONFIG: {
model: 'mock-claude-model',
maxTokens: 4000,
temperature: 0.7,
debug: false
},
sanitizePrompt: jest.fn((prompt) => prompt),
truncate: jest.fn((text) => text),
isSilentMode: jest.fn(() => false),
findTaskById: jest.fn((tasks, id) =>
tasks.find((t) => t.id === parseInt(id))
),
findProjectRoot: jest.fn(() => '/mock/project/root'),
resolveEnvVariable: jest.fn((varName) => `mock_${varName}`),
ensureTagMetadata: jest.fn()
}));
jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
formatDependenciesWithStatus: jest.fn(),
displayBanner: jest.fn(),
displayTaskList: jest.fn(),
startLoadingIndicator: jest.fn(() => ({ stop: jest.fn() })),
stopLoadingIndicator: jest.fn(),
createProgressBar: jest.fn(() => ' MOCK_PROGRESS_BAR '),
getStatusWithColor: jest.fn((status) => status),
getComplexityWithColor: jest.fn((score) => `Score: ${score}`)
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/dependency-manager.js',
() => ({
validateAndFixDependencies: jest.fn(),
validateTaskDependencies: jest.fn()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/config-manager.js',
() => ({
getDebugFlag: jest.fn(() => false),
getProjectName: jest.fn(() => 'Test Project')
})
);
// Import the mocked modules
const { readJSON, writeJSON, log, findProjectRoot, ensureTagMetadata } =
await import('../../../../../scripts/modules/utils.js');
const { formatDependenciesWithStatus } = await import(
'../../../../../scripts/modules/ui.js'
);
const { validateAndFixDependencies } = await import(
'../../../../../scripts/modules/dependency-manager.js'
);
const fs = (await import('fs')).default;
const path = (await import('path')).default;
// Import the module under test
const { default: generateTaskFiles } = await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
);
describe('generateTaskFiles', () => {
// Sample task data for testing - updated to tagged format
const sampleTasksData = {
master: {
tasks: [
{
id: 1,
title: 'Task 1',
description: 'First task description',
status: 'pending',
dependencies: [],
priority: 'high',
details: 'Detailed information for task 1',
testStrategy: 'Test strategy for task 1'
},
{
id: 2,
title: 'Task 2',
description: 'Second task description',
status: 'pending',
dependencies: [1],
priority: 'medium',
details: 'Detailed information for task 2',
testStrategy: 'Test strategy for task 2'
},
{
id: 3,
title: 'Task with Subtasks',
description: 'Task with subtasks description',
status: 'pending',
dependencies: [1, 2],
priority: 'high',
details: 'Detailed information for task 3',
testStrategy: 'Test strategy for task 3',
subtasks: [
{
id: 1,
title: 'Subtask 1',
description: 'First subtask',
status: 'pending',
dependencies: [],
details: 'Details for subtask 1'
},
{
id: 2,
title: 'Subtask 2',
description: 'Second subtask',
status: 'pending',
dependencies: [1],
details: 'Details for subtask 2'
}
]
}
],
metadata: {
projectName: 'Test Project',
created: '2024-01-01T00:00:00.000Z',
updated: '2024-01-01T00:00:00.000Z'
}
}
};
beforeEach(() => {
jest.clearAllMocks();
// Mock readJSON to return the full tagged structure
readJSON.mockImplementation((tasksPath, projectRoot, tag) => {
if (tag && sampleTasksData[tag]) {
return {
...sampleTasksData[tag],
tag,
_rawTaggedData: sampleTasksData
};
}
// Default to master if no tag or tag not found
return {
...sampleTasksData.master,
tag: 'master',
_rawTaggedData: sampleTasksData
};
});
});
test('should generate task files from tasks.json - working test', async () => {
// Set up mocks for this specific test
fs.existsSync.mockReturnValue(true);
// Call the function
const tasksPath = 'tasks/tasks.json';
const outputDir = 'tasks';
await generateTaskFiles(tasksPath, outputDir, {
tag: 'master',
mcpLog: { info: jest.fn() }
});
// Verify the data was read with new signature, defaulting to master
expect(readJSON).toHaveBeenCalledWith(tasksPath, undefined, 'master');
// Verify dependencies were validated with the raw tagged data
expect(validateAndFixDependencies).toHaveBeenCalledWith(
sampleTasksData,
tasksPath,
undefined,
'master'
);
// Verify files were written for each task in the master tag
expect(fs.writeFileSync).toHaveBeenCalledTimes(3);
// Verify specific file paths
expect(fs.writeFileSync).toHaveBeenCalledWith(
'tasks/task_001.txt',
expect.any(String)
);
expect(fs.writeFileSync).toHaveBeenCalledWith(
'tasks/task_002.txt',
expect.any(String)
);
expect(fs.writeFileSync).toHaveBeenCalledWith(
'tasks/task_003.txt',
expect.any(String)
);
});
test('should format dependencies with status indicators', async () => {
// Set up mocks
fs.existsSync.mockReturnValue(true);
formatDependenciesWithStatus.mockReturnValue(
'✅ Task 1 (done), ⏱️ Task 2 (pending)'
);
// Call the function
await generateTaskFiles('tasks/tasks.json', 'tasks', {
tag: 'master',
mcpLog: { info: jest.fn() }
});
// Verify formatDependenciesWithStatus was called for tasks with dependencies
// It will be called multiple times, once for each task that has dependencies.
expect(formatDependenciesWithStatus).toHaveBeenCalled();
});
test('should handle tasks with no subtasks', async () => {
// Create data with tasks that have no subtasks - updated to tagged format
const tasksWithoutSubtasks = {
master: {
tasks: [
{
id: 1,
title: 'Simple Task',
description: 'A simple task without subtasks',
status: 'pending',
dependencies: [],
priority: 'medium',
details: 'Simple task details',
testStrategy: 'Simple test strategy'
}
],
metadata: {
projectName: 'Test Project',
created: '2024-01-01T00:00:00.000Z',
updated: '2024-01-01T00:00:00.000Z'
}
}
};
// Update the mock for this specific test case
readJSON.mockImplementation((tasksPath, projectRoot, tag) => {
return {
...tasksWithoutSubtasks.master,
tag: 'master',
_rawTaggedData: tasksWithoutSubtasks
};
});
fs.existsSync.mockReturnValue(true);
// Call the function
await generateTaskFiles('tasks/tasks.json', 'tasks', {
tag: 'master',
mcpLog: { info: jest.fn() }
});
// Verify the file was written
expect(fs.writeFileSync).toHaveBeenCalledTimes(1);
expect(fs.writeFileSync).toHaveBeenCalledWith(
'tasks/task_001.txt',
expect.any(String)
);
});
test('should validate dependencies before generating files', async () => {
// Set up mocks
fs.existsSync.mockReturnValue(true);
// Call the function
await generateTaskFiles('tasks/tasks.json', 'tasks', {
tag: 'master',
mcpLog: { info: jest.fn() }
});
// Verify validateAndFixDependencies was called with the raw tagged data
expect(validateAndFixDependencies).toHaveBeenCalledWith(
sampleTasksData,
'tasks/tasks.json',
undefined,
'master'
);
});
});

View File

@@ -42,13 +42,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
})
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager.js',
() => ({

View File

@@ -10,13 +10,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
traverseDependencies: jest.fn(() => [])
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/is-task-dependent.js',
() => ({
@@ -36,11 +29,6 @@ jest.unstable_mockModule(
const { readJSON, writeJSON, log } = await import(
'../../../../../scripts/modules/utils.js'
);
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
const { default: moveTask } = await import(
'../../../../../scripts/modules/task-manager/move-task.js'

View File

@@ -192,13 +192,6 @@ jest.unstable_mockModule(
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/models.js',
() => ({
@@ -353,13 +346,6 @@ const { displayParsePrdStart, displayParsePrdSummary } = await import(
'../../../../../src/ui/parse-prd.js'
);
// Note: getDefaultNumTasks validation happens at CLI/MCP level, not in the main parse-prd module
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
const fs = await import('fs');
const path = await import('path');

View File

@@ -16,13 +16,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
isSilentMode: jest.fn(() => false)
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
// fs is used for file deletion side-effects stub the methods we touch
jest.unstable_mockModule('fs', () => ({
existsSync: jest.fn(() => true),
@@ -35,11 +28,6 @@ jest.unstable_mockModule('fs', () => ({
const { readJSON, writeJSON, log } = await import(
'../../../../../scripts/modules/utils.js'
);
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
const fs = await import('fs');
// Import module under test (AFTER mocks in place)

View File

@@ -24,13 +24,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
getCurrentTag: jest.fn(() => 'master')
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
formatDependenciesWithStatus: jest.fn(),
displayBanner: jest.fn(),
@@ -87,12 +80,6 @@ const { readJSON, writeJSON, log, findTaskById } = await import(
'../../../../../scripts/modules/utils.js'
);
const generateTaskFiles = (
await import(
'../../../../../scripts/modules/task-manager/generate-task-files.js'
)
).default;
const updateSingleTaskStatus = (
await import(
'../../../../../scripts/modules/task-manager/update-single-task-status.js'

View File

@@ -44,13 +44,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
displayContextAnalysis: jest.fn()
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/ai-services-unified.js',
() => ({

View File

@@ -42,13 +42,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
displayContextAnalysis: jest.fn()
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/ai-services-unified.js',
() => ({

View File

@@ -55,13 +55,6 @@ jest.unstable_mockModule(
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({
default: jest.fn().mockResolvedValue()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/prompt-manager.js',
() => ({