mirror of
https://github.com/eyaltoledano/claude-task-master.git
synced 2026-01-30 06:12:05 +00:00
feat: deprecate generate command (#1425)
This commit is contained in:
5
.changeset/rich-kings-fold.md
Normal file
5
.changeset/rich-kings-fold.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"task-master-ai": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Deprecated generate command
|
||||||
@@ -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 add-dependency --id=<id> --depends-on=<id> # Add task dependency
|
||||||
task-master move --from=<id> --to=<id> # Reorganize task hierarchy
|
task-master move --from=<id> --to=<id> # Reorganize task hierarchy
|
||||||
task-master validate-dependencies # Check for dependency issues
|
task-master validate-dependencies # Check for dependency issues
|
||||||
task-master generate # Update task markdown files (usually auto-called)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Files & Project Structure
|
## Key Files & Project Structure
|
||||||
@@ -361,9 +360,6 @@ task-master models --set-fallback gpt-4o-mini
|
|||||||
### Task File Sync Issues
|
### Task File Sync Issues
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Regenerate task files from tasks.json
|
|
||||||
task-master generate
|
|
||||||
|
|
||||||
# Fix dependency issues
|
# Fix dependency issues
|
||||||
task-master fix-dependencies
|
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 `tasks.json` - use commands instead
|
||||||
- Never manually edit `.taskmaster/config.json` - use `task-master models`
|
- 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
|
### Claude Code Session Management
|
||||||
|
|
||||||
|
|||||||
@@ -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,6,7 --from-tag=backlog --to-tag=done --with-dependencies
|
||||||
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-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
|
# Add rules after initialization
|
||||||
task-master rules add windsurf,roo,vscode
|
task-master rules add windsurf,roo,vscode
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -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.
|
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
|
## Set Task Status
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -107,9 +107,6 @@ task-master list
|
|||||||
|
|
||||||
# Show the next task to work on
|
# Show the next task to work on
|
||||||
task-master next
|
task-master next
|
||||||
|
|
||||||
# Generate task files
|
|
||||||
task-master generate
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting up Cursor AI Integration
|
## 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
|
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
|
## AI-Driven Development Workflow
|
||||||
|
|
||||||
The Cursor agent is pre-configured (via the rules file) to follow this workflow:
|
The Cursor agent is pre-configured (via the rules file) to follow this workflow:
|
||||||
|
|||||||
@@ -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'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ import { parsePRDDirect } from './direct-functions/parse-prd.js';
|
|||||||
import { updateTasksDirect } from './direct-functions/update-tasks.js';
|
import { updateTasksDirect } from './direct-functions/update-tasks.js';
|
||||||
import { updateTaskByIdDirect } from './direct-functions/update-task-by-id.js';
|
import { updateTaskByIdDirect } from './direct-functions/update-task-by-id.js';
|
||||||
import { updateSubtaskByIdDirect } from './direct-functions/update-subtask-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 { setTaskStatusDirect } from './direct-functions/set-task-status.js';
|
||||||
import { nextTaskDirect } from './direct-functions/next-task.js';
|
import { nextTaskDirect } from './direct-functions/next-task.js';
|
||||||
import { expandTaskDirect } from './direct-functions/expand-task.js';
|
import { expandTaskDirect } from './direct-functions/expand-task.js';
|
||||||
@@ -50,7 +49,6 @@ export const directFunctions = new Map([
|
|||||||
['updateTasksDirect', updateTasksDirect],
|
['updateTasksDirect', updateTasksDirect],
|
||||||
['updateTaskByIdDirect', updateTaskByIdDirect],
|
['updateTaskByIdDirect', updateTaskByIdDirect],
|
||||||
['updateSubtaskByIdDirect', updateSubtaskByIdDirect],
|
['updateSubtaskByIdDirect', updateSubtaskByIdDirect],
|
||||||
['generateTaskFilesDirect', generateTaskFilesDirect],
|
|
||||||
['setTaskStatusDirect', setTaskStatusDirect],
|
['setTaskStatusDirect', setTaskStatusDirect],
|
||||||
['nextTaskDirect', nextTaskDirect],
|
['nextTaskDirect', nextTaskDirect],
|
||||||
['expandTaskDirect', expandTaskDirect],
|
['expandTaskDirect', expandTaskDirect],
|
||||||
@@ -88,7 +86,6 @@ export {
|
|||||||
updateTasksDirect,
|
updateTasksDirect,
|
||||||
updateTaskByIdDirect,
|
updateTaskByIdDirect,
|
||||||
updateSubtaskByIdDirect,
|
updateSubtaskByIdDirect,
|
||||||
generateTaskFilesDirect,
|
|
||||||
setTaskStatusDirect,
|
setTaskStatusDirect,
|
||||||
nextTaskDirect,
|
nextTaskDirect,
|
||||||
expandTaskDirect,
|
expandTaskDirect,
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ import { registerParsePRDTool } from './parse-prd.js';
|
|||||||
import { registerUpdateTool } from './update.js';
|
import { registerUpdateTool } from './update.js';
|
||||||
import { registerUpdateTaskTool } from './update-task.js';
|
import { registerUpdateTaskTool } from './update-task.js';
|
||||||
import { registerUpdateSubtaskTool } from './update-subtask.js';
|
import { registerUpdateSubtaskTool } from './update-subtask.js';
|
||||||
import { registerGenerateTool } from './generate.js';
|
|
||||||
import { registerNextTaskTool } from './next-task.js';
|
import { registerNextTaskTool } from './next-task.js';
|
||||||
import { registerExpandTaskTool } from './expand-task.js';
|
import { registerExpandTaskTool } from './expand-task.js';
|
||||||
import { registerAddTaskTool } from './add-task.js';
|
import { registerAddTaskTool } from './add-task.js';
|
||||||
@@ -72,7 +71,6 @@ export const toolRegistry = {
|
|||||||
next_task: registerNextTaskTool,
|
next_task: registerNextTaskTool,
|
||||||
complexity_report: registerComplexityReportTool,
|
complexity_report: registerComplexityReportTool,
|
||||||
set_task_status: registerSetTaskStatusTool,
|
set_task_status: registerSetTaskStatusTool,
|
||||||
generate: registerGenerateTool,
|
|
||||||
add_task: registerAddTaskTool,
|
add_task: registerAddTaskTool,
|
||||||
add_subtask: registerAddSubtaskTool,
|
add_subtask: registerAddSubtaskTool,
|
||||||
update: registerUpdateTool,
|
update: registerUpdateTool,
|
||||||
@@ -128,7 +126,6 @@ export const standardTools = [
|
|||||||
'expand_all',
|
'expand_all',
|
||||||
'add_subtask',
|
'add_subtask',
|
||||||
'remove_task',
|
'remove_task',
|
||||||
'generate',
|
|
||||||
'add_task',
|
'add_task',
|
||||||
'complexity_report'
|
'complexity_report'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -25,7 +25,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
parsePRD,
|
parsePRD,
|
||||||
updateTasks,
|
updateTasks,
|
||||||
generateTaskFiles,
|
|
||||||
expandTask,
|
expandTask,
|
||||||
expandAllTasks,
|
expandAllTasks,
|
||||||
clearSubtasks,
|
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
|
// Register All Commands from @tm/cli
|
||||||
// ========================================
|
// ========================================
|
||||||
@@ -3340,33 +3303,6 @@ Examples:
|
|||||||
console.log('\n' + chalk.yellow.bold('Next Steps:'));
|
console.log('\n' + chalk.yellow.bold('Next Steps:'));
|
||||||
result.tips.forEach((t) => console.log(chalk.white(` • ${t}`)));
|
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
|
// Helper function to handle within-tag move logic
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import {
|
|||||||
|
|
||||||
import { displayBanner } from './ui.js';
|
import { displayBanner } from './ui.js';
|
||||||
|
|
||||||
import generateTaskFiles from './task-manager/generate-task-files.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structured error class for dependency operations
|
* Structured error class for dependency operations
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { findTaskById } from './utils.js';
|
|||||||
import parsePRD from './task-manager/parse-prd/index.js';
|
import parsePRD from './task-manager/parse-prd/index.js';
|
||||||
import updateTasks from './task-manager/update-tasks.js';
|
import updateTasks from './task-manager/update-tasks.js';
|
||||||
import updateTaskById from './task-manager/update-task-by-id.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 setTaskStatus from './task-manager/set-task-status.js';
|
||||||
import updateSingleTaskStatus from './task-manager/update-single-task-status.js';
|
import updateSingleTaskStatus from './task-manager/update-single-task-status.js';
|
||||||
import listTasks from './task-manager/list-tasks.js';
|
import listTasks from './task-manager/list-tasks.js';
|
||||||
@@ -40,7 +39,6 @@ export {
|
|||||||
updateTasks,
|
updateTasks,
|
||||||
updateTaskById,
|
updateTaskById,
|
||||||
updateSubtaskById,
|
updateSubtaskById,
|
||||||
generateTaskFiles,
|
|
||||||
setTaskStatus,
|
setTaskStatus,
|
||||||
updateSingleTaskStatus,
|
updateSingleTaskStatus,
|
||||||
listTasks,
|
listTasks,
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import { generateObjectService } from '../ai-services-unified.js';
|
|||||||
import { getDefaultPriority, hasCodebaseAnalysis } from '../config-manager.js';
|
import { getDefaultPriority, hasCodebaseAnalysis } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import ContextGatherer from '../utils/contextGatherer.js';
|
import ContextGatherer from '../utils/contextGatherer.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
|
||||||
import { COMMAND_SCHEMAS } from '../../../src/schemas/registry.js';
|
import { COMMAND_SCHEMAS } from '../../../src/schemas/registry.js';
|
||||||
import {
|
import {
|
||||||
TASK_PRIORITY_OPTIONS,
|
TASK_PRIORITY_OPTIONS,
|
||||||
|
|||||||
@@ -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;
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { readJSON, writeJSON, log, findTaskById } from '../utils.js';
|
import { readJSON, writeJSON, log, findTaskById } from '../utils.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
|
||||||
import taskExists from './task-exists.js';
|
import taskExists from './task-exists.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { displayBanner } from '../ui.js';
|
|||||||
import { validateTaskDependencies } from '../dependency-manager.js';
|
import { validateTaskDependencies } from '../dependency-manager.js';
|
||||||
import { getDebugFlag } from '../config-manager.js';
|
import { getDebugFlag } from '../config-manager.js';
|
||||||
import updateSingleTaskStatus from './update-single-task-status.js';
|
import updateSingleTaskStatus from './update-single-task-status.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
|
||||||
import {
|
import {
|
||||||
isValidTaskStatus,
|
isValidTaskStatus,
|
||||||
TASK_STATUS_OPTIONS
|
TASK_STATUS_OPTIONS
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import {
|
|||||||
import { generateTextService } from '../ai-services-unified.js';
|
import { generateTextService } from '../ai-services-unified.js';
|
||||||
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
|
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
|
||||||
import { ContextGatherer } from '../utils/contextGatherer.js';
|
import { ContextGatherer } from '../utils/contextGatherer.js';
|
||||||
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
||||||
import { tryUpdateViaRemote } from '@tm/bridge';
|
import { tryUpdateViaRemote } from '@tm/bridge';
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
|
|
||||||
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
|
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
|
||||||
import { generateObjectService } from '../ai-services-unified.js';
|
import { generateObjectService } from '../ai-services-unified.js';
|
||||||
import { COMMAND_SCHEMAS } from '../../../src/schemas/registry.js';
|
import { COMMAND_SCHEMAS } from '../../../src/schemas/registry.js';
|
||||||
import { getModelConfiguration } from './models.js';
|
import { getModelConfiguration } from './models.js';
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getToolCounts,
|
getToolCategories,
|
||||||
getToolCategories
|
getToolCounts
|
||||||
} from '../../mcp-server/src/tools/tool-registry.js';
|
} from '../../mcp-server/src/tools/tool-registry.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,8 +14,8 @@ import {
|
|||||||
*/
|
*/
|
||||||
export const EXPECTED_TOOL_COUNTS = {
|
export const EXPECTED_TOOL_COUNTS = {
|
||||||
core: 7,
|
core: 7,
|
||||||
standard: 15,
|
standard: 14,
|
||||||
total: 44
|
total: 43
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { jest } from '@jest/globals';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { jest } from '@jest/globals';
|
||||||
|
|
||||||
// --- Define mock functions ---
|
// --- Define mock functions ---
|
||||||
const mockMoveTasksBetweenTags = jest.fn();
|
const mockMoveTasksBetweenTags = jest.fn();
|
||||||
const mockMoveTask = jest.fn();
|
const mockMoveTask = jest.fn();
|
||||||
const mockGenerateTaskFiles = jest.fn();
|
|
||||||
const mockLog = jest.fn();
|
const mockLog = jest.fn();
|
||||||
|
|
||||||
// --- Setup mocks using unstable_mockModule ---
|
// --- 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', () => ({
|
jest.unstable_mockModule('../../../scripts/modules/utils.js', () => ({
|
||||||
log: mockLog,
|
log: mockLog,
|
||||||
readJSON: jest.fn(),
|
readJSON: jest.fn(),
|
||||||
@@ -58,7 +50,7 @@ jest.unstable_mockModule('chalk', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// --- Import modules (AFTER mock setup) ---
|
// --- Import modules (AFTER mock setup) ---
|
||||||
let moveTaskModule, generateTaskFilesModule, utilsModule, chalk;
|
let moveTaskModule, utilsModule, chalk;
|
||||||
|
|
||||||
describe('Cross-Tag Move CLI Integration', () => {
|
describe('Cross-Tag Move CLI Integration', () => {
|
||||||
// Setup dynamic imports before tests run
|
// Setup dynamic imports before tests run
|
||||||
@@ -66,9 +58,6 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
moveTaskModule = await import(
|
moveTaskModule = await import(
|
||||||
'../../../scripts/modules/task-manager/move-task.js'
|
'../../../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');
|
utilsModule = await import('../../../scripts/modules/utils.js');
|
||||||
chalk = (await import('chalk')).default;
|
chalk = (await import('chalk')).default;
|
||||||
});
|
});
|
||||||
@@ -176,18 +165,6 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
console.log('Next Steps:');
|
console.log('Next Steps:');
|
||||||
result.tips.forEach((t) => console.log(` • ${t}`));
|
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) {
|
} catch (error) {
|
||||||
console.error(chalk.red(`Error: ${error.message}`));
|
console.error(chalk.red(`Error: ${error.message}`));
|
||||||
// Print ID collision guidance similar to CLI help block
|
// 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 () => {
|
it('should move task without dependencies successfully', async () => {
|
||||||
// Mock successful cross-tag move
|
// Mock successful cross-tag move
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: '2',
|
from: '2',
|
||||||
@@ -324,7 +300,6 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
it('should move task with dependencies when --with-dependencies is used', async () => {
|
it('should move task with dependencies when --with-dependencies is used', async () => {
|
||||||
// Mock successful cross-tag move with dependencies
|
// Mock successful cross-tag move with dependencies
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: '1',
|
from: '1',
|
||||||
@@ -350,7 +325,6 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
it('should break dependencies when --ignore-dependencies is used', async () => {
|
it('should break dependencies when --ignore-dependencies is used', async () => {
|
||||||
// Mock successful cross-tag move with dependency breaking
|
// Mock successful cross-tag move with dependency breaking
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: '1',
|
from: '1',
|
||||||
@@ -376,7 +350,6 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
it('should create target tag if it does not exist', async () => {
|
it('should create target tag if it does not exist', async () => {
|
||||||
// Mock successful cross-tag move to new tag
|
// Mock successful cross-tag move to new tag
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: '2',
|
from: '2',
|
||||||
@@ -567,24 +540,11 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
ignoreDependencies: false
|
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 () => {
|
it('should move multiple tasks with comma-separated IDs successfully', async () => {
|
||||||
// Mock successful cross-tag move for multiple tasks
|
// Mock successful cross-tag move for multiple tasks
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: '1,2,3',
|
from: '1,2,3',
|
||||||
@@ -604,19 +564,6 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
ignoreDependencies: undefined
|
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
|
// 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 () => {
|
it('should handle whitespace in comma-separated task IDs', async () => {
|
||||||
// Mock successful cross-tag move with whitespace
|
// Mock successful cross-tag move with whitespace
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: ' 1 , 2 , 3 ', // Whitespace around IDs and commas
|
from: ' 1 , 2 , 3 ', // Whitespace around IDs and commas
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ const mockExpandTask = jest
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockGenerateTaskFiles = jest.fn().mockResolvedValue(true);
|
|
||||||
const mockFindTaskById = jest.fn();
|
const mockFindTaskById = jest.fn();
|
||||||
const mockTaskExists = jest.fn().mockReturnValue(true);
|
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
|
// Mock task-manager.js to avoid real operations
|
||||||
jest.mock('../../../scripts/modules/task-manager.js', () => ({
|
jest.mock('../../../scripts/modules/task-manager.js', () => ({
|
||||||
expandTask: mockExpandTask,
|
expandTask: mockExpandTask,
|
||||||
generateTaskFiles: mockGenerateTaskFiles,
|
|
||||||
findTaskById: mockFindTaskById,
|
findTaskById: mockFindTaskById,
|
||||||
taskExists: mockTaskExists
|
taskExists: mockTaskExists
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { jest } from '@jest/globals';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
import { jest } from '@jest/globals';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
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
|
// Import the modules we'll be testing after mocking
|
||||||
const { moveTasksBetweenTags } = await import(
|
const { moveTasksBetweenTags } = await import(
|
||||||
'../../scripts/modules/task-manager/move-task.js'
|
'../../scripts/modules/task-manager/move-task.js'
|
||||||
|
|||||||
@@ -71,10 +71,6 @@ jest.mock('../../scripts/modules/ui.js', () => ({
|
|||||||
displayBanner: jest.fn()
|
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
|
// Use a temporary path for test files - Jest will clean up the temp directory
|
||||||
const TEST_TASKS_PATH = '/tmp/jest-test-tasks.json';
|
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', () => ({
|
await jest.unstable_mockModule('../../scripts/modules/ui.js', () => ({
|
||||||
displayBanner: jest.fn()
|
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
|
// Set up test data that matches the issue report
|
||||||
// Clone fixture data before each test to prevent mutation issues
|
// Clone fixture data before each test to prevent mutation issues
|
||||||
mockReadJSON.mockImplementation(() =>
|
mockReadJSON.mockImplementation(() =>
|
||||||
|
|||||||
@@ -121,14 +121,6 @@ jest.unstable_mockModule('../../scripts/modules/ui.js', () => ({
|
|||||||
displayAiUsageSummary: jest.fn()
|
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
|
// Mock stream parser
|
||||||
jest.unstable_mockModule('../../src/utils/stream-parser.js', () => {
|
jest.unstable_mockModule('../../src/utils/stream-parser.js', () => {
|
||||||
// Define mock StreamingError class
|
// Define mock StreamingError class
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const mockConfig = {
|
|||||||
// Core functionality mocks (always needed)
|
// Core functionality mocks (always needed)
|
||||||
core: {
|
core: {
|
||||||
moveTasksBetweenTags: true,
|
moveTasksBetweenTags: true,
|
||||||
generateTaskFiles: true,
|
|
||||||
readJSON: true,
|
readJSON: true,
|
||||||
initTaskMaster: true,
|
initTaskMaster: true,
|
||||||
findProjectRoot: true
|
findProjectRoot: true
|
||||||
@@ -48,9 +47,6 @@ function createMockFactory(config = mockConfig) {
|
|||||||
if (config.core?.moveTasksBetweenTags) {
|
if (config.core?.moveTasksBetweenTags) {
|
||||||
mocks.moveTasksBetweenTags = createMock('moveTasksBetweenTags');
|
mocks.moveTasksBetweenTags = createMock('moveTasksBetweenTags');
|
||||||
}
|
}
|
||||||
if (config.core?.generateTaskFiles) {
|
|
||||||
mocks.generateTaskFiles = createMock('generateTaskFiles');
|
|
||||||
}
|
|
||||||
if (config.core?.readJSON) {
|
if (config.core?.readJSON) {
|
||||||
mocks.readJSON = createMock('readJSON');
|
mocks.readJSON = createMock('readJSON');
|
||||||
}
|
}
|
||||||
@@ -80,14 +76,9 @@ function setupMocks(config = mockConfig) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (config.core?.readJSON || config.core?.findProjectRoot) {
|
||||||
config.core?.generateTaskFiles ||
|
|
||||||
config.core?.readJSON ||
|
|
||||||
config.core?.findProjectRoot
|
|
||||||
) {
|
|
||||||
jest.mock('../../../../../scripts/modules/utils.js', () => ({
|
jest.mock('../../../../../scripts/modules/utils.js', () => ({
|
||||||
findProjectRoot: mocks.findProjectRoot,
|
findProjectRoot: mocks.findProjectRoot,
|
||||||
generateTaskFiles: mocks.generateTaskFiles,
|
|
||||||
readJSON: mocks.readJSON,
|
readJSON: mocks.readJSON,
|
||||||
// Minimal set of utils that might be used
|
// Minimal set of utils that might be used
|
||||||
log: jest.fn(),
|
log: jest.fn(),
|
||||||
@@ -172,20 +163,6 @@ async function handleCrossTagMove(moveContext, options) {
|
|||||||
const sourceTagHasTasks =
|
const sourceTagHasTasks =
|
||||||
tasksData && Array.isArray(tasksData.tasks) && tasksData.tasks.length > 0;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +193,6 @@ describe('CLI Move Command Cross-Tag Functionality', () => {
|
|||||||
|
|
||||||
mocks.initTaskMaster.mockReturnValue(mockTaskMaster);
|
mocks.initTaskMaster.mockReturnValue(mockTaskMaster);
|
||||||
mocks.findProjectRoot.mockReturnValue('/test/project');
|
mocks.findProjectRoot.mockReturnValue('/test/project');
|
||||||
mocks.generateTaskFiles.mockResolvedValue();
|
|
||||||
mocks.readJSON.mockReturnValue({
|
mocks.readJSON.mockReturnValue({
|
||||||
tasks: [
|
tasks: [
|
||||||
{ id: 1, title: 'Test Task 1' },
|
{ id: 1, title: 'Test Task 1' },
|
||||||
@@ -482,14 +458,12 @@ describe('CLI Move Command Cross-Tag Functionality', () => {
|
|||||||
const minimalConfig = {
|
const minimalConfig = {
|
||||||
core: {
|
core: {
|
||||||
moveTasksBetweenTags: true,
|
moveTasksBetweenTags: true,
|
||||||
generateTaskFiles: true,
|
|
||||||
readJSON: true
|
readJSON: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const minimalMocks = createMockFactory(minimalConfig);
|
const minimalMocks = createMockFactory(minimalConfig);
|
||||||
expect(minimalMocks.moveTasksBetweenTags).toBeDefined();
|
expect(minimalMocks.moveTasksBetweenTags).toBeDefined();
|
||||||
expect(minimalMocks.generateTaskFiles).toBeDefined();
|
|
||||||
expect(minimalMocks.readJSON).toBeDefined();
|
expect(minimalMocks.readJSON).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -498,15 +472,13 @@ describe('CLI Move Command Cross-Tag Functionality', () => {
|
|||||||
const selectiveConfig = {
|
const selectiveConfig = {
|
||||||
core: {
|
core: {
|
||||||
moveTasksBetweenTags: true,
|
moveTasksBetweenTags: true,
|
||||||
generateTaskFiles: false, // Disabled
|
readJSON: false // Disabled
|
||||||
readJSON: true
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectiveMocks = createMockFactory(selectiveConfig);
|
const selectiveMocks = createMockFactory(selectiveConfig);
|
||||||
expect(selectiveMocks.moveTasksBetweenTags).toBeDefined();
|
expect(selectiveMocks.moveTasksBetweenTags).toBeDefined();
|
||||||
expect(selectiveMocks.generateTaskFiles).toBeUndefined();
|
expect(selectiveMocks.readJSON).toBeUndefined();
|
||||||
expect(selectiveMocks.readJSON).toBeDefined();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,13 +44,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock task-manager.js
|
// Mock task-manager.js
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../../../../../scripts/modules/task-manager.js',
|
|
||||||
() => ({
|
|
||||||
generateTaskFiles: jest.fn()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mock external libraries
|
// Mock external libraries
|
||||||
jest.unstable_mockModule('chalk', () => ({
|
jest.unstable_mockModule('chalk', () => ({
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -23,12 +23,6 @@ jest.unstable_mockModule(
|
|||||||
'../../../../../scripts/modules/task-manager.js',
|
'../../../../../scripts/modules/task-manager.js',
|
||||||
() => mockTaskManager
|
() => mockTaskManager
|
||||||
);
|
);
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js',
|
|
||||||
() => ({
|
|
||||||
default: mockGenerateTaskFiles
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const addSubtask = (
|
const addSubtask = (
|
||||||
await import('../../../../../scripts/modules/task-manager/add-subtask.js')
|
await import('../../../../../scripts/modules/task-manager/add-subtask.js')
|
||||||
|
|||||||
@@ -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(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/prompt-manager.js',
|
'../../../../../scripts/modules/prompt-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
@@ -173,12 +166,6 @@ const { generateObjectService } = await import(
|
|||||||
'../../../../../scripts/modules/ai-services-unified.js'
|
'../../../../../scripts/modules/ai-services-unified.js'
|
||||||
);
|
);
|
||||||
|
|
||||||
const generateTaskFiles = (
|
|
||||||
await import(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
|
||||||
)
|
|
||||||
).default;
|
|
||||||
|
|
||||||
// Import the module under test
|
// Import the module under test
|
||||||
const { default: addTask } = await import(
|
const { default: addTask } = await import(
|
||||||
'../../../../../scripts/modules/task-manager/add-task.js'
|
'../../../../../scripts/modules/task-manager/add-task.js'
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
|||||||
displayBanner: jest.fn()
|
displayBanner: jest.fn()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js',
|
|
||||||
() => ({
|
|
||||||
default: jest.fn().mockResolvedValue()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mock external UI libraries
|
// Mock external UI libraries
|
||||||
jest.unstable_mockModule('chalk', () => ({
|
jest.unstable_mockModule('chalk', () => ({
|
||||||
default: {
|
default: {
|
||||||
@@ -68,11 +61,6 @@ const mockExit = jest.spyOn(process, 'exit').mockImplementation((code) => {
|
|||||||
// Import the mocked modules
|
// Import the mocked modules
|
||||||
const { readJSON, writeJSON, log, findTaskById, ensureTagMetadata } =
|
const { readJSON, writeJSON, log, findTaskById, ensureTagMetadata } =
|
||||||
await import('../../../../../scripts/modules/utils.js');
|
await import('../../../../../scripts/modules/utils.js');
|
||||||
const generateTaskFiles = (
|
|
||||||
await import(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
|
||||||
)
|
|
||||||
).default;
|
|
||||||
|
|
||||||
// Import the module under test
|
// Import the module under test
|
||||||
const { default: clearSubtasks } = await import(
|
const { default: clearSubtasks } = await import(
|
||||||
@@ -116,7 +104,6 @@ describe('clearSubtasks', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
writeJSON.mockResolvedValue();
|
writeJSON.mockResolvedValue();
|
||||||
generateTaskFiles.mockResolvedValue();
|
|
||||||
log.mockImplementation(() => {});
|
log.mockImplementation(() => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -191,7 +178,6 @@ describe('clearSubtasks', () => {
|
|||||||
expect(readJSON).toHaveBeenCalledWith(tasksPath, undefined, 'master');
|
expect(readJSON).toHaveBeenCalledWith(tasksPath, undefined, 'master');
|
||||||
// Should not write the file if no changes were made
|
// Should not write the file if no changes were made
|
||||||
expect(writeJSON).not.toHaveBeenCalled();
|
expect(writeJSON).not.toHaveBeenCalled();
|
||||||
expect(generateTaskFiles).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle non-existent task IDs gracefully', () => {
|
test('should handle non-existent task IDs gracefully', () => {
|
||||||
@@ -208,7 +194,6 @@ describe('clearSubtasks', () => {
|
|||||||
expect(log).toHaveBeenCalledWith('error', 'Task 99 not found');
|
expect(log).toHaveBeenCalledWith('error', 'Task 99 not found');
|
||||||
// Should not write the file if no changes were made
|
// Should not write the file if no changes were made
|
||||||
expect(writeJSON).not.toHaveBeenCalled();
|
expect(writeJSON).not.toHaveBeenCalled();
|
||||||
expect(generateTaskFiles).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle multiple task IDs including both valid and non-existent IDs', () => {
|
test('should handle multiple task IDs including both valid and non-existent IDs', () => {
|
||||||
|
|||||||
@@ -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(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/prompt-manager.js',
|
'../../../../../scripts/modules/prompt-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
@@ -246,12 +239,6 @@ const { generateObjectService } = await import(
|
|||||||
'../../../../../scripts/modules/ai-services-unified.js'
|
'../../../../../scripts/modules/ai-services-unified.js'
|
||||||
);
|
);
|
||||||
|
|
||||||
const generateTaskFiles = (
|
|
||||||
await import(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
|
||||||
)
|
|
||||||
).default;
|
|
||||||
|
|
||||||
const { getDefaultSubtasks } = await import(
|
const { getDefaultSubtasks } = await import(
|
||||||
'../../../../../scripts/modules/config-manager.js'
|
'../../../../../scripts/modules/config-manager.js'
|
||||||
);
|
);
|
||||||
@@ -365,7 +352,6 @@ describe('expandTask', () => {
|
|||||||
findProjectRoot.mockReturnValue('/mock/project/root');
|
findProjectRoot.mockReturnValue('/mock/project/root');
|
||||||
|
|
||||||
writeJSON.mockResolvedValue();
|
writeJSON.mockResolvedValue();
|
||||||
generateTaskFiles.mockResolvedValue();
|
|
||||||
log.mockImplementation(() => {});
|
log.mockImplementation(() => {});
|
||||||
|
|
||||||
// Mock console.log to avoid output during tests
|
// Mock console.log to avoid output during tests
|
||||||
|
|||||||
@@ -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'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -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(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/task-manager.js',
|
'../../../../../scripts/modules/task-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
@@ -10,13 +10,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
|
|||||||
traverseDependencies: jest.fn(() => [])
|
traverseDependencies: jest.fn(() => [])
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js',
|
|
||||||
() => ({
|
|
||||||
default: jest.fn().mockResolvedValue()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/task-manager/is-task-dependent.js',
|
'../../../../../scripts/modules/task-manager/is-task-dependent.js',
|
||||||
() => ({
|
() => ({
|
||||||
@@ -36,11 +29,6 @@ jest.unstable_mockModule(
|
|||||||
const { readJSON, writeJSON, log } = await import(
|
const { readJSON, writeJSON, log } = await import(
|
||||||
'../../../../../scripts/modules/utils.js'
|
'../../../../../scripts/modules/utils.js'
|
||||||
);
|
);
|
||||||
const generateTaskFiles = (
|
|
||||||
await import(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
|
||||||
)
|
|
||||||
).default;
|
|
||||||
|
|
||||||
const { default: moveTask } = await import(
|
const { default: moveTask } = await import(
|
||||||
'../../../../../scripts/modules/task-manager/move-task.js'
|
'../../../../../scripts/modules/task-manager/move-task.js'
|
||||||
|
|||||||
@@ -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(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/task-manager/models.js',
|
'../../../../../scripts/modules/task-manager/models.js',
|
||||||
() => ({
|
() => ({
|
||||||
@@ -353,13 +346,6 @@ const { displayParsePrdStart, displayParsePrdSummary } = await import(
|
|||||||
'../../../../../src/ui/parse-prd.js'
|
'../../../../../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 fs = await import('fs');
|
||||||
const path = await import('path');
|
const path = await import('path');
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
|
|||||||
isSilentMode: jest.fn(() => false)
|
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
|
// fs is used for file deletion side-effects – stub the methods we touch
|
||||||
jest.unstable_mockModule('fs', () => ({
|
jest.unstable_mockModule('fs', () => ({
|
||||||
existsSync: jest.fn(() => true),
|
existsSync: jest.fn(() => true),
|
||||||
@@ -35,11 +28,6 @@ jest.unstable_mockModule('fs', () => ({
|
|||||||
const { readJSON, writeJSON, log } = await import(
|
const { readJSON, writeJSON, log } = await import(
|
||||||
'../../../../../scripts/modules/utils.js'
|
'../../../../../scripts/modules/utils.js'
|
||||||
);
|
);
|
||||||
const generateTaskFiles = (
|
|
||||||
await import(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
|
||||||
)
|
|
||||||
).default;
|
|
||||||
const fs = await import('fs');
|
const fs = await import('fs');
|
||||||
|
|
||||||
// Import module under test (AFTER mocks in place)
|
// Import module under test (AFTER mocks in place)
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
|
|||||||
getCurrentTag: jest.fn(() => 'master')
|
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', () => ({
|
jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
||||||
formatDependenciesWithStatus: jest.fn(),
|
formatDependenciesWithStatus: jest.fn(),
|
||||||
displayBanner: jest.fn(),
|
displayBanner: jest.fn(),
|
||||||
@@ -87,12 +80,6 @@ const { readJSON, writeJSON, log, findTaskById } = await import(
|
|||||||
'../../../../../scripts/modules/utils.js'
|
'../../../../../scripts/modules/utils.js'
|
||||||
);
|
);
|
||||||
|
|
||||||
const generateTaskFiles = (
|
|
||||||
await import(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
|
||||||
)
|
|
||||||
).default;
|
|
||||||
|
|
||||||
const updateSingleTaskStatus = (
|
const updateSingleTaskStatus = (
|
||||||
await import(
|
await import(
|
||||||
'../../../../../scripts/modules/task-manager/update-single-task-status.js'
|
'../../../../../scripts/modules/task-manager/update-single-task-status.js'
|
||||||
|
|||||||
@@ -44,13 +44,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
|||||||
displayContextAnalysis: jest.fn()
|
displayContextAnalysis: jest.fn()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js',
|
|
||||||
() => ({
|
|
||||||
default: jest.fn().mockResolvedValue()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/ai-services-unified.js',
|
'../../../../../scripts/modules/ai-services-unified.js',
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
@@ -42,13 +42,6 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
|||||||
displayContextAnalysis: jest.fn()
|
displayContextAnalysis: jest.fn()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js',
|
|
||||||
() => ({
|
|
||||||
default: jest.fn().mockResolvedValue()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/ai-services-unified.js',
|
'../../../../../scripts/modules/ai-services-unified.js',
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
@@ -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(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/prompt-manager.js',
|
'../../../../../scripts/modules/prompt-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user