Merge pull request #15 from eyaltoledano/complexity-fix
Fix: Improve 'parse-prd' command and CLI help consistency Fixed an issue with analyzeTaskComplexity implementation. Stubs 3 tests for analyzeTaskComplexity, to be done later Fixes issues with table displays Fixes an issue which incorrectly used an outdated Perplexity model by default Fixes the interpolation of the suggested task expansion prompt in the complexity-report command.
This commit is contained in:
@@ -4,6 +4,7 @@ PERPLEXITY_API_KEY=pplx-abcde # For research (recommended but optional)
|
|||||||
|
|
||||||
# Optional - defaults shown
|
# Optional - defaults shown
|
||||||
MODEL=claude-3-7-sonnet-20250219 # Recommended models: claude-3-7-sonnet-20250219, claude-3-opus-20240229
|
MODEL=claude-3-7-sonnet-20250219 # Recommended models: claude-3-7-sonnet-20250219, claude-3-opus-20240229
|
||||||
|
PERPLEXITY_MODEL=sonar-pro # Make sure you have access to sonar-pro otherwise you can use sonar regular.
|
||||||
MAX_TOKENS=4000 # Maximum tokens for model responses
|
MAX_TOKENS=4000 # Maximum tokens for model responses
|
||||||
TEMPERATURE=0.7 # Temperature for model responses (0.0-1.0)
|
TEMPERATURE=0.7 # Temperature for model responses (0.0-1.0)
|
||||||
DEBUG=false # Enable debug logging (true/false)
|
DEBUG=false # Enable debug logging (true/false)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { dirname, resolve } from 'path';
|
|||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { Command } from 'commander';
|
import { Command } from 'commander';
|
||||||
|
import { displayHelp, displayBanner } from '../scripts/modules/ui.js';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
@@ -41,7 +42,18 @@ const program = new Command();
|
|||||||
program
|
program
|
||||||
.name('task-master')
|
.name('task-master')
|
||||||
.description('Claude Task Master CLI')
|
.description('Claude Task Master CLI')
|
||||||
.version(version);
|
.version(version)
|
||||||
|
.addHelpText('afterAll', () => {
|
||||||
|
// Use the same help display function as dev.js for consistency
|
||||||
|
displayHelp();
|
||||||
|
return ''; // Return empty string to prevent commander's default help
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add custom help option to directly call our help display
|
||||||
|
program.helpOption('-h, --help', 'Display help information');
|
||||||
|
program.on('--help', () => {
|
||||||
|
displayHelp();
|
||||||
|
});
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('init')
|
.command('init')
|
||||||
@@ -124,11 +136,12 @@ program
|
|||||||
program
|
program
|
||||||
.command('parse-prd')
|
.command('parse-prd')
|
||||||
.description('Parse a PRD file and generate tasks')
|
.description('Parse a PRD file and generate tasks')
|
||||||
.argument('<file>', 'Path to the PRD file')
|
.argument('[file]', 'Path to the PRD file')
|
||||||
.option('-o, --output <file>', 'Output file path', 'tasks/tasks.json')
|
.option('-o, --output <file>', 'Output file path', 'tasks/tasks.json')
|
||||||
.option('-n, --num-tasks <number>', 'Number of tasks to generate', '10')
|
.option('-n, --num-tasks <number>', 'Number of tasks to generate', '10')
|
||||||
.action((file, options) => {
|
.action((file, options) => {
|
||||||
const args = ['parse-prd', file];
|
const args = ['parse-prd'];
|
||||||
|
if (file) args.push(file);
|
||||||
if (options.output) args.push('--output', options.output);
|
if (options.output) args.push('--output', options.output);
|
||||||
if (options.numTasks) args.push('--num-tasks', options.numTasks);
|
if (options.numTasks) args.push('--num-tasks', options.numTasks);
|
||||||
runDevScript(args);
|
runDevScript(args);
|
||||||
@@ -164,12 +177,12 @@ program
|
|||||||
|
|
||||||
program
|
program
|
||||||
.command('expand')
|
.command('expand')
|
||||||
.description('Expand tasks with subtasks')
|
.description('Break down tasks into detailed subtasks')
|
||||||
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
||||||
.option('-i, --id <id>', 'Task ID to expand')
|
.option('-i, --id <id>', 'Task ID to expand')
|
||||||
.option('-a, --all', 'Expand all tasks')
|
.option('-a, --all', 'Expand all tasks')
|
||||||
.option('-n, --num <number>', 'Number of subtasks to generate')
|
.option('-n, --num <number>', 'Number of subtasks to generate')
|
||||||
.option('-r, --no-research', 'Disable Perplexity AI for research-backed subtask generation')
|
.option('--research', 'Enable Perplexity AI for research-backed subtask generation')
|
||||||
.option('-p, --prompt <text>', 'Additional context to guide subtask generation')
|
.option('-p, --prompt <text>', 'Additional context to guide subtask generation')
|
||||||
.option('--force', 'Force regeneration of subtasks for tasks that already have them')
|
.option('--force', 'Force regeneration of subtasks for tasks that already have them')
|
||||||
.action((options) => {
|
.action((options) => {
|
||||||
@@ -178,7 +191,7 @@ program
|
|||||||
if (options.id) args.push('--id', options.id);
|
if (options.id) args.push('--id', options.id);
|
||||||
if (options.all) args.push('--all');
|
if (options.all) args.push('--all');
|
||||||
if (options.num) args.push('--num', options.num);
|
if (options.num) args.push('--num', options.num);
|
||||||
if (!options.research) args.push('--no-research');
|
if (options.research) args.push('--research');
|
||||||
if (options.prompt) args.push('--prompt', options.prompt);
|
if (options.prompt) args.push('--prompt', options.prompt);
|
||||||
if (options.force) args.push('--force');
|
if (options.force) args.push('--force');
|
||||||
runDevScript(args);
|
runDevScript(args);
|
||||||
@@ -234,7 +247,7 @@ program
|
|||||||
|
|
||||||
program
|
program
|
||||||
.command('show')
|
.command('show')
|
||||||
.description('Show details of a specific task by ID')
|
.description('Display detailed information about a specific task')
|
||||||
.argument('[id]', 'Task ID to show')
|
.argument('[id]', 'Task ID to show')
|
||||||
.option('-i, --id <id>', 'Task ID to show (alternative to argument)')
|
.option('-i, --id <id>', 'Task ID to show (alternative to argument)')
|
||||||
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
||||||
@@ -304,4 +317,11 @@ program
|
|||||||
runDevScript(args);
|
runDevScript(args);
|
||||||
});
|
});
|
||||||
|
|
||||||
program.parse(process.argv);
|
program.parse(process.argv);
|
||||||
|
|
||||||
|
// Show help if no command was provided (just 'task-master' with no args)
|
||||||
|
if (process.argv.length <= 2) {
|
||||||
|
displayBanner();
|
||||||
|
displayHelp();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.9.16",
|
"version": "0.9.18",
|
||||||
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -72,4 +72,4 @@
|
|||||||
"mock-fs": "^5.5.0",
|
"mock-fs": "^5.5.0",
|
||||||
"supertest": "^7.1.0"
|
"supertest": "^7.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -542,7 +542,7 @@ function createProjectStructure(projectName, projectDescription, projectVersion,
|
|||||||
chalk.white('1. ') + chalk.yellow('Rename .env.example to .env and add your ANTHROPIC_API_KEY and PERPLEXITY_API_KEY') + '\n' +
|
chalk.white('1. ') + chalk.yellow('Rename .env.example to .env and add your ANTHROPIC_API_KEY and PERPLEXITY_API_KEY') + '\n' +
|
||||||
chalk.white('2. ') + chalk.yellow('Discuss your idea with AI, and once ready ask for a PRD using the example_prd.txt file, and save what you get to scripts/PRD.txt') + '\n' +
|
chalk.white('2. ') + chalk.yellow('Discuss your idea with AI, and once ready ask for a PRD using the example_prd.txt file, and save what you get to scripts/PRD.txt') + '\n' +
|
||||||
chalk.white('3. ') + chalk.yellow('Ask Cursor Agent to parse your PRD.txt and generate tasks') + '\n' +
|
chalk.white('3. ') + chalk.yellow('Ask Cursor Agent to parse your PRD.txt and generate tasks') + '\n' +
|
||||||
chalk.white(' └─ ') + chalk.dim('You can also run ') + chalk.cyan('npm run parse-prd -- --input=<your-prd-file.txt>') + '\n' +
|
chalk.white(' └─ ') + chalk.dim('You can also run ') + chalk.cyan('task-master parse-prd <your-prd-file.txt>') + '\n' +
|
||||||
chalk.white('4. ') + chalk.yellow('Ask Cursor to analyze the complexity of your tasks') + '\n' +
|
chalk.white('4. ') + chalk.yellow('Ask Cursor to analyze the complexity of your tasks') + '\n' +
|
||||||
chalk.white('5. ') + chalk.yellow('Ask Cursor which task is next to determine where to start') + '\n' +
|
chalk.white('5. ') + chalk.yellow('Ask Cursor which task is next to determine where to start') + '\n' +
|
||||||
chalk.white('6. ') + chalk.yellow('Ask Cursor to expand any complex tasks that are too large or complex.') + '\n' +
|
chalk.white('6. ') + chalk.yellow('Ask Cursor to expand any complex tasks that are too large or complex.') + '\n' +
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ async function generateSubtasksWithPerplexity(task, numSubtasks = 3, nextSubtask
|
|||||||
log('info', `Researching context for task ${task.id}: ${task.title}`);
|
log('info', `Researching context for task ${task.id}: ${task.title}`);
|
||||||
const perplexityClient = getPerplexityClient();
|
const perplexityClient = getPerplexityClient();
|
||||||
|
|
||||||
const PERPLEXITY_MODEL = process.env.PERPLEXITY_MODEL || 'sonar-small-online';
|
const PERPLEXITY_MODEL = process.env.PERPLEXITY_MODEL || 'sonar-pro';
|
||||||
const researchLoadingIndicator = startLoadingIndicator('Researching best practices with Perplexity AI...');
|
const researchLoadingIndicator = startLoadingIndicator('Researching best practices with Perplexity AI...');
|
||||||
|
|
||||||
// Formulate research query based on task
|
// Formulate research query based on task
|
||||||
@@ -493,13 +493,13 @@ function parseSubtasksFromText(text, startId, expectedCount, parentTaskId) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a prompt for complexity analysis
|
* Generate a prompt for complexity analysis
|
||||||
* @param {Array} tasksData - Tasks data
|
* @param {Object} tasksData - Tasks data object containing tasks array
|
||||||
* @returns {string} Generated prompt
|
* @returns {string} Generated prompt
|
||||||
*/
|
*/
|
||||||
function generateComplexityAnalysisPrompt(tasksData) {
|
function generateComplexityAnalysisPrompt(tasksData) {
|
||||||
return `Analyze the complexity of the following tasks and provide recommendations for subtask breakdown:
|
return `Analyze the complexity of the following tasks and provide recommendations for subtask breakdown:
|
||||||
|
|
||||||
${tasksData.map(task => `
|
${tasksData.tasks.map(task => `
|
||||||
Task ID: ${task.id}
|
Task ID: ${task.id}
|
||||||
Title: ${task.title}
|
Title: ${task.title}
|
||||||
Description: ${task.description}
|
Description: ${task.description}
|
||||||
|
|||||||
@@ -52,10 +52,27 @@ function registerCommands(programInstance) {
|
|||||||
programInstance
|
programInstance
|
||||||
.command('parse-prd')
|
.command('parse-prd')
|
||||||
.description('Parse a PRD file and generate tasks')
|
.description('Parse a PRD file and generate tasks')
|
||||||
.argument('<file>', 'Path to the PRD file')
|
.argument('[file]', 'Path to the PRD file')
|
||||||
.option('-o, --output <file>', 'Output file path', 'tasks/tasks.json')
|
.option('-o, --output <file>', 'Output file path', 'tasks/tasks.json')
|
||||||
.option('-n, --num-tasks <number>', 'Number of tasks to generate', '10')
|
.option('-n, --num-tasks <number>', 'Number of tasks to generate', '10')
|
||||||
.action(async (file, options) => {
|
.action(async (file, options) => {
|
||||||
|
if (!file) {
|
||||||
|
console.log(chalk.yellow('No PRD file specified.'));
|
||||||
|
console.log(boxen(
|
||||||
|
chalk.white.bold('Parse PRD Help') + '\n\n' +
|
||||||
|
chalk.cyan('Usage:') + '\n' +
|
||||||
|
` task-master parse-prd <prd-file.txt> [options]\n\n` +
|
||||||
|
chalk.cyan('Options:') + '\n' +
|
||||||
|
' -o, --output <file> Output file path (default: "tasks/tasks.json")\n' +
|
||||||
|
' -n, --num-tasks <number> Number of tasks to generate (default: 10)\n\n' +
|
||||||
|
chalk.cyan('Example:') + '\n' +
|
||||||
|
' task-master parse-prd requirements.txt --num-tasks 15\n\n' +
|
||||||
|
chalk.yellow('Note: This command will generate tasks from a PRD document and will overwrite any existing tasks.json file.'),
|
||||||
|
{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const numTasks = parseInt(options.numTasks, 10);
|
const numTasks = parseInt(options.numTasks, 10);
|
||||||
const outputPath = options.output;
|
const outputPath = options.output;
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ The changes described in the prompt should be applied to ALL tasks in the list.`
|
|||||||
log('info', 'Using Perplexity AI for research-backed task updates');
|
log('info', 'Using Perplexity AI for research-backed task updates');
|
||||||
|
|
||||||
// Call Perplexity AI using format consistent with ai-services.js
|
// Call Perplexity AI using format consistent with ai-services.js
|
||||||
const perplexityModel = process.env.PERPLEXITY_MODEL || 'sonar-small-online';
|
const perplexityModel = process.env.PERPLEXITY_MODEL || 'sonar-pro';
|
||||||
const result = await perplexity.chat.completions.create({
|
const result = await perplexity.chat.completions.create({
|
||||||
model: perplexityModel,
|
model: perplexityModel,
|
||||||
messages: [
|
messages: [
|
||||||
@@ -379,7 +379,17 @@ function generateTaskFiles(tasksPath, outputDir) {
|
|||||||
// Handle numeric dependencies to other subtasks
|
// Handle numeric dependencies to other subtasks
|
||||||
const foundSubtask = task.subtasks.find(st => st.id === depId);
|
const foundSubtask = task.subtasks.find(st => st.id === depId);
|
||||||
if (foundSubtask) {
|
if (foundSubtask) {
|
||||||
return `${depId} (${foundSubtask.status || 'pending'})`;
|
const isDone = foundSubtask.status === 'done' || foundSubtask.status === 'completed';
|
||||||
|
const isInProgress = foundSubtask.status === 'in-progress';
|
||||||
|
|
||||||
|
// Use consistent color formatting instead of emojis
|
||||||
|
if (isDone) {
|
||||||
|
return chalk.green.bold(`${task.id}.${depId}`);
|
||||||
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(`${task.id}.${depId}`);
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(`${task.id}.${depId}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return depId.toString();
|
return depId.toString();
|
||||||
@@ -675,8 +685,20 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
`Priority: ${chalk.white(nextTask.priority || 'medium')} Dependencies: ${formatDependenciesWithStatus(nextTask.dependencies, data.tasks, true)}` :
|
`Priority: ${chalk.white(nextTask.priority || 'medium')} Dependencies: ${formatDependenciesWithStatus(nextTask.dependencies, data.tasks, true)}` :
|
||||||
chalk.yellow('No eligible tasks found. All tasks are either completed or have unsatisfied dependencies.');
|
chalk.yellow('No eligible tasks found. All tasks are either completed or have unsatisfied dependencies.');
|
||||||
|
|
||||||
// Get terminal width
|
// Get terminal width - more reliable method
|
||||||
const terminalWidth = process.stdout.columns || 80;
|
let terminalWidth;
|
||||||
|
try {
|
||||||
|
// Try to get the actual terminal columns
|
||||||
|
terminalWidth = process.stdout.columns;
|
||||||
|
} catch (e) {
|
||||||
|
// Fallback if columns cannot be determined
|
||||||
|
log('debug', 'Could not determine terminal width, using default');
|
||||||
|
}
|
||||||
|
// Ensure we have a reasonable default if detection fails
|
||||||
|
terminalWidth = terminalWidth || 80;
|
||||||
|
|
||||||
|
// Ensure terminal width is at least a minimum value to prevent layout issues
|
||||||
|
terminalWidth = Math.max(terminalWidth, 80);
|
||||||
|
|
||||||
// Create dashboard content
|
// Create dashboard content
|
||||||
const projectDashboardContent =
|
const projectDashboardContent =
|
||||||
@@ -794,30 +816,17 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the previously defined terminalWidth for responsive table
|
// COMPLETELY REVISED TABLE APPROACH
|
||||||
|
// Define fixed column widths based on terminal size
|
||||||
|
const idWidth = 10;
|
||||||
|
const statusWidth = 20;
|
||||||
|
const priorityWidth = 10;
|
||||||
|
const depsWidth = 25;
|
||||||
|
|
||||||
// Define column widths based on percentage of available space
|
// Calculate title width from available space
|
||||||
// Reserve minimum widths for ID, Status, Priority and Dependencies
|
const titleWidth = terminalWidth - idWidth - statusWidth - priorityWidth - depsWidth - 10; // 10 for borders and padding
|
||||||
const minIdWidth = 4;
|
|
||||||
const minStatusWidth = 12;
|
|
||||||
const minPriorityWidth = 8;
|
|
||||||
const minDepsWidth = 15;
|
|
||||||
|
|
||||||
// Calculate available space for the title column
|
// Create a table with correct borders and spacing
|
||||||
const minFixedColumnsWidth = minIdWidth + minStatusWidth + minPriorityWidth + minDepsWidth;
|
|
||||||
const tableMargin = 10; // Account for table borders and padding
|
|
||||||
const availableTitleWidth = Math.max(30, terminalWidth - minFixedColumnsWidth - tableMargin);
|
|
||||||
|
|
||||||
// Scale column widths proportionally
|
|
||||||
const colWidths = [
|
|
||||||
minIdWidth,
|
|
||||||
availableTitleWidth,
|
|
||||||
minStatusWidth,
|
|
||||||
minPriorityWidth,
|
|
||||||
minDepsWidth
|
|
||||||
];
|
|
||||||
|
|
||||||
// Create a table for tasks
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
head: [
|
head: [
|
||||||
chalk.cyan.bold('ID'),
|
chalk.cyan.bold('ID'),
|
||||||
@@ -826,61 +835,118 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
chalk.cyan.bold('Priority'),
|
chalk.cyan.bold('Priority'),
|
||||||
chalk.cyan.bold('Dependencies')
|
chalk.cyan.bold('Dependencies')
|
||||||
],
|
],
|
||||||
colWidths: colWidths,
|
colWidths: [idWidth, titleWidth, statusWidth, priorityWidth, depsWidth],
|
||||||
wordWrap: true
|
style: {
|
||||||
|
head: [], // No special styling for header
|
||||||
|
border: [], // No special styling for border
|
||||||
|
compact: false // Use default spacing
|
||||||
|
},
|
||||||
|
wordWrap: true,
|
||||||
|
wrapOnWordBoundary: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add tasks to the table
|
// Process tasks for the table
|
||||||
filteredTasks.forEach(task => {
|
filteredTasks.forEach(task => {
|
||||||
// Get a list of task dependencies
|
// Format dependencies with status indicators (colored)
|
||||||
const formattedDeps = formatDependenciesWithStatus(task.dependencies, data.tasks, true);
|
let depText = 'None';
|
||||||
|
if (task.dependencies && task.dependencies.length > 0) {
|
||||||
|
// Use the proper formatDependenciesWithStatus function for colored status
|
||||||
|
depText = formatDependenciesWithStatus(task.dependencies, data.tasks, true);
|
||||||
|
} else {
|
||||||
|
depText = chalk.gray('None');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any ANSI codes or confusing characters
|
||||||
|
const cleanTitle = task.title.replace(/\n/g, ' ');
|
||||||
|
|
||||||
|
// Get priority color
|
||||||
|
const priorityColor = {
|
||||||
|
'high': chalk.red,
|
||||||
|
'medium': chalk.yellow,
|
||||||
|
'low': chalk.gray
|
||||||
|
}[task.priority || 'medium'] || chalk.white;
|
||||||
|
|
||||||
|
// Format status
|
||||||
|
const status = getStatusWithColor(task.status, true);
|
||||||
|
|
||||||
|
// Add the row without truncating dependencies
|
||||||
table.push([
|
table.push([
|
||||||
task.id,
|
task.id.toString(),
|
||||||
truncate(task.title, availableTitleWidth - 3), // -3 for table cell padding
|
truncate(cleanTitle, titleWidth - 3),
|
||||||
getStatusWithColor(task.status),
|
status,
|
||||||
chalk.white(task.priority || 'medium'),
|
priorityColor(truncate(task.priority || 'medium', priorityWidth - 2)),
|
||||||
formattedDeps
|
depText // No truncation for dependencies
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Add subtasks if requested
|
// Add subtasks if requested
|
||||||
if (withSubtasks && task.subtasks && task.subtasks.length > 0) {
|
if (withSubtasks && task.subtasks && task.subtasks.length > 0) {
|
||||||
task.subtasks.forEach(subtask => {
|
task.subtasks.forEach(subtask => {
|
||||||
// Format subtask dependencies
|
// Format subtask dependencies with status indicators
|
||||||
let subtaskDeps = '';
|
let subtaskDepText = 'None';
|
||||||
|
|
||||||
if (subtask.dependencies && subtask.dependencies.length > 0) {
|
if (subtask.dependencies && subtask.dependencies.length > 0) {
|
||||||
subtaskDeps = subtask.dependencies.map(depId => {
|
// Handle both subtask-to-subtask and subtask-to-task dependencies
|
||||||
|
const formattedDeps = subtask.dependencies.map(depId => {
|
||||||
// Check if it's a dependency on another subtask
|
// Check if it's a dependency on another subtask
|
||||||
const foundSubtask = task.subtasks.find(st => st.id === depId);
|
if (typeof depId === 'number' && depId < 100) {
|
||||||
|
const foundSubtask = task.subtasks.find(st => st.id === depId);
|
||||||
if (foundSubtask) {
|
if (foundSubtask) {
|
||||||
const isDone = foundSubtask.status === 'done' || foundSubtask.status === 'completed';
|
const isDone = foundSubtask.status === 'done' || foundSubtask.status === 'completed';
|
||||||
const statusIcon = isDone ?
|
const isInProgress = foundSubtask.status === 'in-progress';
|
||||||
chalk.green('✅') :
|
|
||||||
chalk.yellow('⏱️');
|
// Use consistent color formatting instead of emojis
|
||||||
|
if (isDone) {
|
||||||
return `${statusIcon} ${chalk.cyan(`${task.id}.${depId}`)}`;
|
return chalk.green.bold(`${task.id}.${depId}`);
|
||||||
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(`${task.id}.${depId}`);
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(`${task.id}.${depId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Default to regular task dependency
|
||||||
|
const depTask = data.tasks.find(t => t.id === depId);
|
||||||
|
if (depTask) {
|
||||||
|
const isDone = depTask.status === 'done' || depTask.status === 'completed';
|
||||||
|
const isInProgress = depTask.status === 'in-progress';
|
||||||
|
// Use the same color scheme as in formatDependenciesWithStatus
|
||||||
|
if (isDone) {
|
||||||
|
return chalk.green.bold(`${depId}`);
|
||||||
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(`${depId}`);
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(`${depId}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return chalk.cyan(depId.toString());
|
return chalk.cyan(depId.toString());
|
||||||
}).join(', ');
|
}).join(', ');
|
||||||
} else {
|
|
||||||
subtaskDeps = chalk.gray('None');
|
subtaskDepText = formattedDeps || chalk.gray('None');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the subtask row without truncating dependencies
|
||||||
table.push([
|
table.push([
|
||||||
`${task.id}.${subtask.id}`,
|
`${task.id}.${subtask.id}`,
|
||||||
chalk.dim(`└─ ${truncate(subtask.title, availableTitleWidth - 5)}`), // -5 for the "└─ " prefix
|
chalk.dim(`└─ ${truncate(subtask.title, titleWidth - 5)}`),
|
||||||
getStatusWithColor(subtask.status),
|
getStatusWithColor(subtask.status, true),
|
||||||
chalk.dim('-'),
|
chalk.dim('-'),
|
||||||
subtaskDeps
|
subtaskDepText // No truncation for dependencies
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(table.toString());
|
// Ensure we output the table even if it had to wrap
|
||||||
|
try {
|
||||||
|
console.log(table.toString());
|
||||||
|
} catch (err) {
|
||||||
|
log('error', `Error rendering table: ${err.message}`);
|
||||||
|
|
||||||
|
// Fall back to simpler output
|
||||||
|
console.log(chalk.yellow('\nFalling back to simple task list due to terminal width constraints:'));
|
||||||
|
filteredTasks.forEach(task => {
|
||||||
|
console.log(`${chalk.cyan(task.id)}: ${chalk.white(task.title)} - ${getStatusWithColor(task.status)}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Show filter info if applied
|
// Show filter info if applied
|
||||||
if (statusFilter) {
|
if (statusFilter) {
|
||||||
@@ -891,8 +957,8 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
// Define priority colors
|
// Define priority colors
|
||||||
const priorityColors = {
|
const priorityColors = {
|
||||||
'high': chalk.red.bold,
|
'high': chalk.red.bold,
|
||||||
'medium': chalk.yellow,
|
'medium': chalk.yellow,
|
||||||
'low': chalk.gray
|
'low': chalk.gray
|
||||||
};
|
};
|
||||||
|
|
||||||
// Show next task box in a prominent color
|
// Show next task box in a prominent color
|
||||||
@@ -902,25 +968,35 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
if (nextTask.subtasks && nextTask.subtasks.length > 0) {
|
if (nextTask.subtasks && nextTask.subtasks.length > 0) {
|
||||||
subtasksSection = `\n\n${chalk.white.bold('Subtasks:')}\n`;
|
subtasksSection = `\n\n${chalk.white.bold('Subtasks:')}\n`;
|
||||||
subtasksSection += nextTask.subtasks.map(subtask => {
|
subtasksSection += nextTask.subtasks.map(subtask => {
|
||||||
const subtaskStatus = getStatusWithColor(subtask.status || 'pending');
|
// Using a more simplified format for subtask status display
|
||||||
return `${chalk.cyan(`${nextTask.id}.${subtask.id}`)} ${subtaskStatus} ${subtask.title}`;
|
const status = subtask.status || 'pending';
|
||||||
|
const statusColors = {
|
||||||
|
'done': chalk.green,
|
||||||
|
'completed': chalk.green,
|
||||||
|
'pending': chalk.yellow,
|
||||||
|
'in-progress': chalk.blue,
|
||||||
|
'deferred': chalk.gray,
|
||||||
|
'blocked': chalk.red
|
||||||
|
};
|
||||||
|
const statusColor = statusColors[status.toLowerCase()] || chalk.white;
|
||||||
|
return `${chalk.cyan(`${nextTask.id}.${subtask.id}`)} [${statusColor(status)}] ${subtask.title}`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(boxen(
|
console.log(boxen(
|
||||||
chalk.hex('#FF8800').bold(`🔥 Next Task to Work On: #${nextTask.id} - ${nextTask.title}`) + '\n\n' +
|
chalk.hex('#FF8800').bold(`🔥 Next Task to Work On: #${nextTask.id} - ${nextTask.title}`) + '\n\n' +
|
||||||
`${chalk.white('Priority:')} ${priorityColors[nextTask.priority || 'medium'](nextTask.priority || 'medium')} ${chalk.white('Status:')} ${getStatusWithColor(nextTask.status)}\n` +
|
`${chalk.white('Priority:')} ${priorityColors[nextTask.priority || 'medium'](nextTask.priority || 'medium')} ${chalk.white('Status:')} ${getStatusWithColor(nextTask.status, true)}\n` +
|
||||||
`${chalk.white('Dependencies:')} ${formatDependenciesWithStatus(nextTask.dependencies, data.tasks, true)}\n\n` +
|
`${chalk.white('Dependencies:')} ${nextTask.dependencies && nextTask.dependencies.length > 0 ? formatDependenciesWithStatus(nextTask.dependencies, data.tasks, true) : chalk.gray('None')}\n\n` +
|
||||||
`${chalk.white('Description:')} ${nextTask.description}` +
|
`${chalk.white('Description:')} ${nextTask.description}` +
|
||||||
subtasksSection + '\n\n' +
|
subtasksSection + '\n\n' +
|
||||||
`${chalk.cyan('Start working:')} ${chalk.yellow(`task-master set-status --id=${nextTask.id} --status=in-progress`)}\n` +
|
`${chalk.cyan('Start working:')} ${chalk.yellow(`task-master set-status --id=${nextTask.id} --status=in-progress`)}\n` +
|
||||||
`${chalk.cyan('View details:')} ${chalk.yellow(`task-master show ${nextTask.id}`)}`,
|
`${chalk.cyan('View details:')} ${chalk.yellow(`task-master show ${nextTask.id}`)}`,
|
||||||
{
|
{
|
||||||
padding: 1,
|
padding: { left: 2, right: 2, top: 1, bottom: 1 },
|
||||||
borderColor: '#FF8800',
|
borderColor: '#FF8800',
|
||||||
borderStyle: 'round',
|
borderStyle: 'round',
|
||||||
margin: { top: 1, bottom: 1 },
|
margin: { top: 1, bottom: 1 },
|
||||||
title: '⚡ RECOMMENDED NEXT ACTION ⚡',
|
title: '⚡ RECOMMENDED NEXT TASK ⚡',
|
||||||
titleAlignment: 'center',
|
titleAlignment: 'center',
|
||||||
width: terminalWidth - 4, // Use full terminal width minus a small margin
|
width: terminalWidth - 4, // Use full terminal width minus a small margin
|
||||||
fullscreen: false // Keep it expandable but not literally fullscreen
|
fullscreen: false // Keep it expandable but not literally fullscreen
|
||||||
@@ -935,7 +1011,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
borderColor: '#FF8800',
|
borderColor: '#FF8800',
|
||||||
borderStyle: 'round',
|
borderStyle: 'round',
|
||||||
margin: { top: 1, bottom: 1 },
|
margin: { top: 1, bottom: 1 },
|
||||||
title: '⚡ NEXT ACTION ⚡',
|
title: '⚡ NEXT TASK ⚡',
|
||||||
titleAlignment: 'center',
|
titleAlignment: 'center',
|
||||||
width: terminalWidth - 4, // Use full terminal width minus a small margin
|
width: terminalWidth - 4, // Use full terminal width minus a small margin
|
||||||
}
|
}
|
||||||
@@ -962,6 +1038,23 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely apply chalk coloring, stripping ANSI codes when calculating string length
|
||||||
|
* @param {string} text - Original text
|
||||||
|
* @param {Function} colorFn - Chalk color function
|
||||||
|
* @param {number} maxLength - Maximum allowed length
|
||||||
|
* @returns {string} Colored text that won't break table layout
|
||||||
|
*/
|
||||||
|
function safeColor(text, colorFn, maxLength = 0) {
|
||||||
|
if (!text) return '';
|
||||||
|
|
||||||
|
// If maxLength is provided, truncate the text first
|
||||||
|
const baseText = maxLength > 0 ? truncate(text, maxLength) : text;
|
||||||
|
|
||||||
|
// Apply color function if provided, otherwise return as is
|
||||||
|
return colorFn ? colorFn(baseText) : baseText;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand a task with subtasks
|
* Expand a task with subtasks
|
||||||
* @param {number} taskId - Task ID to expand
|
* @param {number} taskId - Task ID to expand
|
||||||
@@ -1087,7 +1180,7 @@ async function expandTask(taskId, numSubtasks = CONFIG.defaultSubtasks, useResea
|
|||||||
`${taskId}.${subtask.id}`,
|
`${taskId}.${subtask.id}`,
|
||||||
truncate(subtask.title, 47),
|
truncate(subtask.title, 47),
|
||||||
deps,
|
deps,
|
||||||
getStatusWithColor(subtask.status)
|
getStatusWithColor(subtask.status, true)
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1663,7 +1756,7 @@ Your response must be a clean JSON array only, following exactly this format:
|
|||||||
DO NOT include any text before or after the JSON array. No explanations, no markdown formatting.`;
|
DO NOT include any text before or after the JSON array. No explanations, no markdown formatting.`;
|
||||||
|
|
||||||
const result = await perplexity.chat.completions.create({
|
const result = await perplexity.chat.completions.create({
|
||||||
model: PERPLEXITY_MODEL,
|
model: process.env.PERPLEXITY_MODEL || 'sonar-pro',
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -1674,8 +1767,8 @@ DO NOT include any text before or after the JSON array. No explanations, no mark
|
|||||||
content: researchPrompt
|
content: researchPrompt
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
temperature: TEMPERATURE,
|
temperature: CONFIG.temperature,
|
||||||
max_tokens: MAX_TOKENS,
|
max_tokens: CONFIG.maxTokens,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extract the response text
|
// Extract the response text
|
||||||
@@ -1796,7 +1889,13 @@ DO NOT include any text before or after the JSON array. No explanations, no mark
|
|||||||
// 3. Replace single quotes with double quotes for property values
|
// 3. Replace single quotes with double quotes for property values
|
||||||
cleanedResponse = cleanedResponse.replace(/:(\s*)'([^']*)'(\s*[,}])/g, ':$1"$2"$3');
|
cleanedResponse = cleanedResponse.replace(/:(\s*)'([^']*)'(\s*[,}])/g, ':$1"$2"$3');
|
||||||
|
|
||||||
// 4. Add a special fallback option if we're still having issues
|
// 4. Fix unterminated strings - common with LLM responses
|
||||||
|
const untermStringPattern = /:(\s*)"([^"]*)(?=[,}])/g;
|
||||||
|
cleanedResponse = cleanedResponse.replace(untermStringPattern, ':$1"$2"');
|
||||||
|
|
||||||
|
// 5. Fix multi-line strings by replacing newlines
|
||||||
|
cleanedResponse = cleanedResponse.replace(/:(\s*)"([^"]*)\n([^"]*)"/g, ':$1"$2 $3"');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
complexityAnalysis = JSON.parse(cleanedResponse);
|
complexityAnalysis = JSON.parse(cleanedResponse);
|
||||||
console.log(chalk.green("Successfully parsed JSON after fixing common issues"));
|
console.log(chalk.green("Successfully parsed JSON after fixing common issues"));
|
||||||
@@ -1913,7 +2012,7 @@ Your response must be a clean JSON array only, following exactly this format:
|
|||||||
DO NOT include any text before or after the JSON array. No explanations, no markdown formatting.`;
|
DO NOT include any text before or after the JSON array. No explanations, no markdown formatting.`;
|
||||||
|
|
||||||
const result = await perplexity.chat.completions.create({
|
const result = await perplexity.chat.completions.create({
|
||||||
model: PERPLEXITY_MODEL,
|
model: process.env.PERPLEXITY_MODEL || 'sonar-pro',
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -1924,8 +2023,8 @@ DO NOT include any text before or after the JSON array. No explanations, no mark
|
|||||||
content: missingTasksResearchPrompt
|
content: missingTasksResearchPrompt
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
temperature: TEMPERATURE,
|
temperature: CONFIG.temperature,
|
||||||
max_tokens: MAX_TOKENS,
|
max_tokens: CONFIG.maxTokens,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extract the response
|
// Extract the response
|
||||||
|
|||||||
@@ -97,24 +97,42 @@ function createProgressBar(percent, length = 30) {
|
|||||||
/**
|
/**
|
||||||
* Get a colored status string based on the status value
|
* Get a colored status string based on the status value
|
||||||
* @param {string} status - Task status (e.g., "done", "pending", "in-progress")
|
* @param {string} status - Task status (e.g., "done", "pending", "in-progress")
|
||||||
|
* @param {boolean} forTable - Whether the status is being displayed in a table
|
||||||
* @returns {string} Colored status string
|
* @returns {string} Colored status string
|
||||||
*/
|
*/
|
||||||
function getStatusWithColor(status) {
|
function getStatusWithColor(status, forTable = false) {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return chalk.gray('❓ unknown');
|
return chalk.gray('❓ unknown');
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusConfig = {
|
const statusConfig = {
|
||||||
'done': { color: chalk.green, icon: '✅' },
|
'done': { color: chalk.green, icon: '✅', tableIcon: '✓' },
|
||||||
'completed': { color: chalk.green, icon: '✅' },
|
'completed': { color: chalk.green, icon: '✅', tableIcon: '✓' },
|
||||||
'pending': { color: chalk.yellow, icon: '⏱️' },
|
'pending': { color: chalk.yellow, icon: '⏱️', tableIcon: '⏱' },
|
||||||
'in-progress': { color: chalk.blue, icon: '🔄' },
|
'in-progress': { color: chalk.hex('#FFA500'), icon: '🔄', tableIcon: '►' },
|
||||||
'deferred': { color: chalk.gray, icon: '⏱️' },
|
'deferred': { color: chalk.gray, icon: '⏱️', tableIcon: '⏱' },
|
||||||
'blocked': { color: chalk.red, icon: '❌' },
|
'blocked': { color: chalk.red, icon: '❌', tableIcon: '✗' },
|
||||||
'review': { color: chalk.magenta, icon: '👀' }
|
'review': { color: chalk.magenta, icon: '👀', tableIcon: '👁' }
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = statusConfig[status.toLowerCase()] || { color: chalk.red, icon: '❌' };
|
const config = statusConfig[status.toLowerCase()] || { color: chalk.red, icon: '❌', tableIcon: '✗' };
|
||||||
|
|
||||||
|
// Use simpler icons for table display to prevent border issues
|
||||||
|
if (forTable) {
|
||||||
|
// Use ASCII characters instead of Unicode for completely stable display
|
||||||
|
const simpleIcons = {
|
||||||
|
'done': '✓',
|
||||||
|
'completed': '✓',
|
||||||
|
'pending': '○',
|
||||||
|
'in-progress': '►',
|
||||||
|
'deferred': 'x',
|
||||||
|
'blocked': '!', // Using plain x character for better compatibility
|
||||||
|
'review': '?' // Using circled dot symbol
|
||||||
|
};
|
||||||
|
const simpleIcon = simpleIcons[status.toLowerCase()] || 'x';
|
||||||
|
return config.color(`${simpleIcon} ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
return config.color(`${config.icon} ${status}`);
|
return config.color(`${config.icon} ${status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,27 +149,91 @@ function formatDependenciesWithStatus(dependencies, allTasks, forConsole = false
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formattedDeps = dependencies.map(depId => {
|
const formattedDeps = dependencies.map(depId => {
|
||||||
const depTask = findTaskById(allTasks, depId);
|
const depIdStr = depId.toString(); // Ensure string format for display
|
||||||
|
|
||||||
|
// Check if it's already a fully qualified subtask ID (like "22.1")
|
||||||
|
if (depIdStr.includes('.')) {
|
||||||
|
const [parentId, subtaskId] = depIdStr.split('.').map(id => parseInt(id, 10));
|
||||||
|
|
||||||
|
// Find the parent task
|
||||||
|
const parentTask = allTasks.find(t => t.id === parentId);
|
||||||
|
if (!parentTask || !parentTask.subtasks) {
|
||||||
|
return forConsole ?
|
||||||
|
chalk.red(`${depIdStr} (Not found)`) :
|
||||||
|
`${depIdStr} (Not found)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the subtask
|
||||||
|
const subtask = parentTask.subtasks.find(st => st.id === subtaskId);
|
||||||
|
if (!subtask) {
|
||||||
|
return forConsole ?
|
||||||
|
chalk.red(`${depIdStr} (Not found)`) :
|
||||||
|
`${depIdStr} (Not found)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format with status
|
||||||
|
const status = subtask.status || 'pending';
|
||||||
|
const isDone = status.toLowerCase() === 'done' || status.toLowerCase() === 'completed';
|
||||||
|
const isInProgress = status.toLowerCase() === 'in-progress';
|
||||||
|
|
||||||
|
if (forConsole) {
|
||||||
|
if (isDone) {
|
||||||
|
return chalk.green.bold(depIdStr);
|
||||||
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(depIdStr);
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(depIdStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusIcon = isDone ? '✅' : '⏱️';
|
||||||
|
return `${statusIcon} ${depIdStr} (${status})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If depId is a number less than 100, it's likely a reference to a subtask ID in the current task
|
||||||
|
// This case is typically handled elsewhere (in task-specific code) before calling this function
|
||||||
|
|
||||||
|
// For regular task dependencies (not subtasks)
|
||||||
|
// Convert string depId to number if needed
|
||||||
|
const numericDepId = typeof depId === 'string' ? parseInt(depId, 10) : depId;
|
||||||
|
|
||||||
|
// Look up the task using the numeric ID
|
||||||
|
const depTask = findTaskById(allTasks, numericDepId);
|
||||||
|
|
||||||
if (!depTask) {
|
if (!depTask) {
|
||||||
return forConsole ?
|
return forConsole ?
|
||||||
chalk.red(`${depId} (Not found)`) :
|
chalk.red(`${depIdStr} (Not found)`) :
|
||||||
`${depId} (Not found)`;
|
`${depIdStr} (Not found)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = depTask.status || 'pending';
|
const status = depTask.status || 'pending';
|
||||||
const isDone = status.toLowerCase() === 'done' || status.toLowerCase() === 'completed';
|
const isDone = status.toLowerCase() === 'done' || status.toLowerCase() === 'completed';
|
||||||
|
const isInProgress = status.toLowerCase() === 'in-progress';
|
||||||
|
|
||||||
|
// Apply colors for console output with more visible options
|
||||||
if (forConsole) {
|
if (forConsole) {
|
||||||
return isDone ?
|
if (isDone) {
|
||||||
chalk.green(`${depId}`) :
|
return chalk.green.bold(depIdStr); // Make completed dependencies bold green
|
||||||
chalk.red(`${depId}`);
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(depIdStr); // Use bright orange for in-progress (more visible)
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(depIdStr); // Make pending dependencies bold red
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusIcon = isDone ? '✅' : '⏱️';
|
const statusIcon = isDone ? '✅' : '⏱️';
|
||||||
return `${statusIcon} ${depId} (${status})`;
|
return `${statusIcon} ${depIdStr} (${status})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (forConsole) {
|
||||||
|
// Handle both single and multiple dependencies
|
||||||
|
if (dependencies.length === 1) {
|
||||||
|
return formattedDeps[0]; // Return the single colored dependency
|
||||||
|
}
|
||||||
|
// Join multiple dependencies with white commas
|
||||||
|
return formattedDeps.join(chalk.white(', '));
|
||||||
|
}
|
||||||
|
|
||||||
return formattedDeps.join(', ');
|
return formattedDeps.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,7 +391,7 @@ function displayHelp() {
|
|||||||
`${chalk.dim('Optional')}${chalk.reset('')}`],
|
`${chalk.dim('Optional')}${chalk.reset('')}`],
|
||||||
[`${chalk.yellow('PERPLEXITY_MODEL')}${chalk.reset('')}`,
|
[`${chalk.yellow('PERPLEXITY_MODEL')}${chalk.reset('')}`,
|
||||||
`${chalk.white('Perplexity model to use')}${chalk.reset('')}`,
|
`${chalk.white('Perplexity model to use')}${chalk.reset('')}`,
|
||||||
`${chalk.dim('Default: sonar-small-online')}${chalk.reset('')}`],
|
`${chalk.dim('Default: sonar-pro')}${chalk.reset('')}`],
|
||||||
[`${chalk.yellow('DEBUG')}${chalk.reset('')}`,
|
[`${chalk.yellow('DEBUG')}${chalk.reset('')}`,
|
||||||
`${chalk.white('Enable debug logging')}${chalk.reset('')}`,
|
`${chalk.white('Enable debug logging')}${chalk.reset('')}`,
|
||||||
`${chalk.dim(`Default: ${CONFIG.debug}`)}${chalk.reset('')}`],
|
`${chalk.dim(`Default: ${CONFIG.debug}`)}${chalk.reset('')}`],
|
||||||
@@ -342,6 +424,18 @@ function getComplexityWithColor(score) {
|
|||||||
return chalk.red(`🔴 ${score}`);
|
return chalk.red(`🔴 ${score}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncate a string to a maximum length and add ellipsis if needed
|
||||||
|
* @param {string} str - The string to truncate
|
||||||
|
* @param {number} maxLength - Maximum length
|
||||||
|
* @returns {string} Truncated string
|
||||||
|
*/
|
||||||
|
function truncateString(str, maxLength) {
|
||||||
|
if (!str) return '';
|
||||||
|
if (str.length <= maxLength) return str;
|
||||||
|
return str.substring(0, maxLength - 3) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the next task to work on
|
* Display the next task to work on
|
||||||
* @param {string} tasksPath - Path to the tasks.json file
|
* @param {string} tasksPath - Path to the tasks.json file
|
||||||
@@ -386,7 +480,8 @@ async function displayNextTask(tasksPath) {
|
|||||||
chars: {
|
chars: {
|
||||||
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
||||||
},
|
},
|
||||||
colWidths: [15, 75]
|
colWidths: [15, Math.min(75, (process.stdout.columns - 20) || 60)],
|
||||||
|
wordWrap: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Priority with color
|
// Priority with color
|
||||||
@@ -424,15 +519,15 @@ async function displayNextTask(tasksPath) {
|
|||||||
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, margin: { top: 1, bottom: 0 }, borderColor: 'magenta', borderStyle: 'round' }
|
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, margin: { top: 1, bottom: 0 }, borderColor: 'magenta', borderStyle: 'round' }
|
||||||
));
|
));
|
||||||
|
|
||||||
// Create a table for subtasks
|
// Create a table for subtasks with improved handling
|
||||||
const subtaskTable = new Table({
|
const subtaskTable = new Table({
|
||||||
head: [
|
head: [
|
||||||
chalk.magenta.bold('ID'),
|
chalk.magenta.bold('ID'),
|
||||||
chalk.magenta.bold('Status'),
|
chalk.magenta.bold('Status'),
|
||||||
chalk.magenta.bold('Title'),
|
chalk.magenta.bold('Title'),
|
||||||
chalk.magenta.bold('Dependencies')
|
chalk.magenta.bold('Deps')
|
||||||
],
|
],
|
||||||
colWidths: [6, 12, 50, 20],
|
colWidths: [6, 12, Math.min(50, process.stdout.columns - 65 || 30), 30],
|
||||||
style: {
|
style: {
|
||||||
head: [],
|
head: [],
|
||||||
border: [],
|
border: [],
|
||||||
@@ -442,7 +537,8 @@ async function displayNextTask(tasksPath) {
|
|||||||
},
|
},
|
||||||
chars: {
|
chars: {
|
||||||
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
||||||
}
|
},
|
||||||
|
wordWrap: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add subtasks to table
|
// Add subtasks to table
|
||||||
@@ -460,11 +556,29 @@ async function displayNextTask(tasksPath) {
|
|||||||
// Format dependencies with correct notation
|
// Format dependencies with correct notation
|
||||||
const formattedDeps = st.dependencies.map(depId => {
|
const formattedDeps = st.dependencies.map(depId => {
|
||||||
if (typeof depId === 'number' && depId < 100) {
|
if (typeof depId === 'number' && depId < 100) {
|
||||||
return `${nextTask.id}.${depId}`;
|
const foundSubtask = nextTask.subtasks.find(st => st.id === depId);
|
||||||
|
if (foundSubtask) {
|
||||||
|
const isDone = foundSubtask.status === 'done' || foundSubtask.status === 'completed';
|
||||||
|
const isInProgress = foundSubtask.status === 'in-progress';
|
||||||
|
|
||||||
|
// Use consistent color formatting instead of emojis
|
||||||
|
if (isDone) {
|
||||||
|
return chalk.green.bold(`${nextTask.id}.${depId}`);
|
||||||
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(`${nextTask.id}.${depId}`);
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(`${nextTask.id}.${depId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chalk.red(`${nextTask.id}.${depId} (Not found)`);
|
||||||
}
|
}
|
||||||
return depId;
|
return depId;
|
||||||
});
|
});
|
||||||
subtaskDeps = formatDependenciesWithStatus(formattedDeps, data.tasks, true);
|
|
||||||
|
// Join the formatted dependencies directly instead of passing to formatDependenciesWithStatus again
|
||||||
|
subtaskDeps = formattedDeps.length === 1
|
||||||
|
? formattedDeps[0]
|
||||||
|
: formattedDeps.join(chalk.white(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtaskTable.push([
|
subtaskTable.push([
|
||||||
@@ -542,7 +656,8 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
chars: {
|
chars: {
|
||||||
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
||||||
},
|
},
|
||||||
colWidths: [15, 75]
|
colWidths: [15, Math.min(75, (process.stdout.columns - 20) || 60)],
|
||||||
|
wordWrap: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add subtask details to table
|
// Add subtask details to table
|
||||||
@@ -550,7 +665,7 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
[chalk.cyan.bold('ID:'), `${task.parentTask.id}.${task.id}`],
|
[chalk.cyan.bold('ID:'), `${task.parentTask.id}.${task.id}`],
|
||||||
[chalk.cyan.bold('Parent Task:'), `#${task.parentTask.id} - ${task.parentTask.title}`],
|
[chalk.cyan.bold('Parent Task:'), `#${task.parentTask.id} - ${task.parentTask.title}`],
|
||||||
[chalk.cyan.bold('Title:'), task.title],
|
[chalk.cyan.bold('Title:'), task.title],
|
||||||
[chalk.cyan.bold('Status:'), getStatusWithColor(task.status || 'pending')],
|
[chalk.cyan.bold('Status:'), getStatusWithColor(task.status || 'pending', true)],
|
||||||
[chalk.cyan.bold('Description:'), task.description || 'No description provided.']
|
[chalk.cyan.bold('Description:'), task.description || 'No description provided.']
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -574,7 +689,7 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, borderColor: 'blue', borderStyle: 'round', margin: { top: 1, bottom: 0 } }
|
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, borderColor: 'blue', borderStyle: 'round', margin: { top: 1, bottom: 0 } }
|
||||||
));
|
));
|
||||||
|
|
||||||
// Create a table with task details
|
// Create a table with task details with improved handling
|
||||||
const taskTable = new Table({
|
const taskTable = new Table({
|
||||||
style: {
|
style: {
|
||||||
head: [],
|
head: [],
|
||||||
@@ -586,7 +701,8 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
chars: {
|
chars: {
|
||||||
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
||||||
},
|
},
|
||||||
colWidths: [15, 75]
|
colWidths: [15, Math.min(75, (process.stdout.columns - 20) || 60)],
|
||||||
|
wordWrap: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Priority with color
|
// Priority with color
|
||||||
@@ -601,7 +717,7 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
taskTable.push(
|
taskTable.push(
|
||||||
[chalk.cyan.bold('ID:'), task.id.toString()],
|
[chalk.cyan.bold('ID:'), task.id.toString()],
|
||||||
[chalk.cyan.bold('Title:'), task.title],
|
[chalk.cyan.bold('Title:'), task.title],
|
||||||
[chalk.cyan.bold('Status:'), getStatusWithColor(task.status || 'pending')],
|
[chalk.cyan.bold('Status:'), getStatusWithColor(task.status || 'pending', true)],
|
||||||
[chalk.cyan.bold('Priority:'), priorityColor(task.priority || 'medium')],
|
[chalk.cyan.bold('Priority:'), priorityColor(task.priority || 'medium')],
|
||||||
[chalk.cyan.bold('Dependencies:'), formatDependenciesWithStatus(task.dependencies, data.tasks, true)],
|
[chalk.cyan.bold('Dependencies:'), formatDependenciesWithStatus(task.dependencies, data.tasks, true)],
|
||||||
[chalk.cyan.bold('Description:'), task.description]
|
[chalk.cyan.bold('Description:'), task.description]
|
||||||
@@ -634,15 +750,15 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, margin: { top: 1, bottom: 0 }, borderColor: 'magenta', borderStyle: 'round' }
|
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, margin: { top: 1, bottom: 0 }, borderColor: 'magenta', borderStyle: 'round' }
|
||||||
));
|
));
|
||||||
|
|
||||||
// Create a table for subtasks
|
// Create a table for subtasks with improved handling
|
||||||
const subtaskTable = new Table({
|
const subtaskTable = new Table({
|
||||||
head: [
|
head: [
|
||||||
chalk.magenta.bold('ID'),
|
chalk.magenta.bold('ID'),
|
||||||
chalk.magenta.bold('Status'),
|
chalk.magenta.bold('Status'),
|
||||||
chalk.magenta.bold('Title'),
|
chalk.magenta.bold('Title'),
|
||||||
chalk.magenta.bold('Dependencies')
|
chalk.magenta.bold('Deps')
|
||||||
],
|
],
|
||||||
colWidths: [6, 12, 50, 20],
|
colWidths: [6, 12, Math.min(50, process.stdout.columns - 65 || 30), 30],
|
||||||
style: {
|
style: {
|
||||||
head: [],
|
head: [],
|
||||||
border: [],
|
border: [],
|
||||||
@@ -652,7 +768,8 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
},
|
},
|
||||||
chars: {
|
chars: {
|
||||||
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
|
||||||
}
|
},
|
||||||
|
wordWrap: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add subtasks to table
|
// Add subtasks to table
|
||||||
@@ -670,11 +787,29 @@ async function displayTaskById(tasksPath, taskId) {
|
|||||||
// Format dependencies with correct notation
|
// Format dependencies with correct notation
|
||||||
const formattedDeps = st.dependencies.map(depId => {
|
const formattedDeps = st.dependencies.map(depId => {
|
||||||
if (typeof depId === 'number' && depId < 100) {
|
if (typeof depId === 'number' && depId < 100) {
|
||||||
return `${task.id}.${depId}`;
|
const foundSubtask = task.subtasks.find(st => st.id === depId);
|
||||||
|
if (foundSubtask) {
|
||||||
|
const isDone = foundSubtask.status === 'done' || foundSubtask.status === 'completed';
|
||||||
|
const isInProgress = foundSubtask.status === 'in-progress';
|
||||||
|
|
||||||
|
// Use consistent color formatting instead of emojis
|
||||||
|
if (isDone) {
|
||||||
|
return chalk.green.bold(`${task.id}.${depId}`);
|
||||||
|
} else if (isInProgress) {
|
||||||
|
return chalk.hex('#FFA500').bold(`${task.id}.${depId}`);
|
||||||
|
} else {
|
||||||
|
return chalk.red.bold(`${task.id}.${depId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chalk.red(`${task.id}.${depId} (Not found)`);
|
||||||
}
|
}
|
||||||
return depId;
|
return depId;
|
||||||
});
|
});
|
||||||
subtaskDeps = formatDependenciesWithStatus(formattedDeps, data.tasks, true);
|
|
||||||
|
// Join the formatted dependencies directly instead of passing to formatDependenciesWithStatus again
|
||||||
|
subtaskDeps = formattedDeps.length === 1
|
||||||
|
? formattedDeps[0]
|
||||||
|
: formattedDeps.join(chalk.white(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtaskTable.push([
|
subtaskTable.push([
|
||||||
@@ -815,37 +950,46 @@ async function displayComplexityReport(reportPath) {
|
|||||||
{ padding: 1, borderColor: 'cyan', borderStyle: 'round', margin: { top: 1, bottom: 1 } }
|
{ padding: 1, borderColor: 'cyan', borderStyle: 'round', margin: { top: 1, bottom: 1 } }
|
||||||
));
|
));
|
||||||
|
|
||||||
// Create table for tasks that need expansion
|
// Get terminal width
|
||||||
if (tasksNeedingExpansion.length > 0) {
|
const terminalWidth = process.stdout.columns || 100; // Default to 100 if can't detect
|
||||||
console.log(boxen(
|
|
||||||
chalk.yellow.bold(`Tasks Recommended for Expansion (${tasksNeedingExpansion.length})`),
|
// Calculate dynamic column widths
|
||||||
{ padding: { left: 2, right: 2, top: 0, bottom: 0 }, margin: { top: 1, bottom: 0 }, borderColor: 'yellow', borderStyle: 'round' }
|
const idWidth = 5;
|
||||||
));
|
const titleWidth = Math.floor(terminalWidth * 0.25); // 25% of width
|
||||||
|
const scoreWidth = 8;
|
||||||
|
const subtasksWidth = 8;
|
||||||
|
// Command column gets the remaining space (minus some buffer for borders)
|
||||||
|
const commandWidth = terminalWidth - idWidth - titleWidth - scoreWidth - subtasksWidth - 10;
|
||||||
|
|
||||||
|
// Create table with new column widths and word wrapping
|
||||||
|
const complexTable = new Table({
|
||||||
|
head: [
|
||||||
|
chalk.yellow.bold('ID'),
|
||||||
|
chalk.yellow.bold('Title'),
|
||||||
|
chalk.yellow.bold('Score'),
|
||||||
|
chalk.yellow.bold('Subtasks'),
|
||||||
|
chalk.yellow.bold('Expansion Command')
|
||||||
|
],
|
||||||
|
colWidths: [idWidth, titleWidth, scoreWidth, subtasksWidth, commandWidth],
|
||||||
|
style: { head: [], border: [] },
|
||||||
|
wordWrap: true,
|
||||||
|
wrapOnWordBoundary: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// When adding rows, don't truncate the expansion command
|
||||||
|
tasksNeedingExpansion.forEach(task => {
|
||||||
|
const expansionCommand = `task-master expand --id=${task.taskId} --num=${task.recommendedSubtasks}${task.expansionPrompt ? ` --prompt="${task.expansionPrompt}"` : ''}`;
|
||||||
|
|
||||||
const complexTable = new Table({
|
complexTable.push([
|
||||||
head: [
|
task.taskId,
|
||||||
chalk.yellow.bold('ID'),
|
truncate(task.taskTitle, titleWidth - 3), // Still truncate title for readability
|
||||||
chalk.yellow.bold('Title'),
|
getComplexityWithColor(task.complexityScore),
|
||||||
chalk.yellow.bold('Score'),
|
task.recommendedSubtasks,
|
||||||
chalk.yellow.bold('Subtasks'),
|
chalk.cyan(expansionCommand) // Don't truncate - allow wrapping
|
||||||
chalk.yellow.bold('Expansion Command')
|
]);
|
||||||
],
|
});
|
||||||
colWidths: [5, 40, 8, 10, 45],
|
|
||||||
style: { head: [], border: [] }
|
console.log(complexTable.toString());
|
||||||
});
|
|
||||||
|
|
||||||
tasksNeedingExpansion.forEach(task => {
|
|
||||||
complexTable.push([
|
|
||||||
task.taskId,
|
|
||||||
truncate(task.taskTitle, 37),
|
|
||||||
getComplexityWithColor(task.complexityScore),
|
|
||||||
task.recommendedSubtasks,
|
|
||||||
chalk.cyan(`task-master expand --id=${task.taskId} --num=${task.recommendedSubtasks}`)
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(complexTable.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create table for simple tasks
|
// Create table for simple tasks
|
||||||
if (simpleTasks.length > 0) {
|
if (simpleTasks.length > 0) {
|
||||||
|
|||||||
@@ -1,171 +1,203 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"generatedAt": "2025-03-21T20:01:53.007Z",
|
"generatedAt": "2025-03-24T20:01:35.986Z",
|
||||||
"tasksAnalyzed": 20,
|
"tasksAnalyzed": 24,
|
||||||
"thresholdScore": 5,
|
"thresholdScore": 5,
|
||||||
"projectName": "Your Project Name",
|
"projectName": "Your Project Name",
|
||||||
"usedResearch": true
|
"usedResearch": false
|
||||||
},
|
},
|
||||||
"complexityAnalysis": [
|
"complexityAnalysis": [
|
||||||
{
|
{
|
||||||
"taskId": 1,
|
"taskId": 1,
|
||||||
"taskTitle": "Implement Task Data Structure",
|
"taskTitle": "Implement Task Data Structure",
|
||||||
"complexityScore": 8,
|
"complexityScore": 7,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Break down the task of creating the tasks.json structure into subtasks focusing on schema design, model creation, validation, file operations, and error handling.",
|
"expansionPrompt": "Break down the implementation of the core tasks.json data structure into subtasks that cover schema design, model implementation, validation, file operations, and error handling. For each subtask, include specific technical requirements and acceptance criteria.",
|
||||||
"reasoning": "This task involves multiple critical components including schema design, model creation, and file operations, each requiring detailed attention and validation."
|
"reasoning": "This task requires designing a foundational data structure that will be used throughout the system. It involves schema design, validation logic, and file system operations, which together represent moderate to high complexity. The task is critical as many other tasks depend on it."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 2,
|
"taskId": 2,
|
||||||
"taskTitle": "Develop Command Line Interface Foundation",
|
"taskTitle": "Develop Command Line Interface Foundation",
|
||||||
"complexityScore": 7,
|
"complexityScore": 6,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Divide the CLI development into subtasks such as command parsing, help documentation, console output, logging system, and global options handling.",
|
"expansionPrompt": "Divide the CLI foundation implementation into subtasks covering Commander.js setup, help documentation creation, console output formatting, and global options handling. Each subtask should specify implementation details and how it integrates with the overall CLI structure.",
|
||||||
"reasoning": "Creating a CLI involves several distinct functionalities that need to be implemented and integrated, each contributing to the overall complexity."
|
"reasoning": "Setting up the CLI foundation requires integrating Commander.js, implementing various command-line options, and establishing the output formatting system. The complexity is moderate as it involves creating the interface layer that users will interact with."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 3,
|
"taskId": 3,
|
||||||
"taskTitle": "Implement Basic Task Operations",
|
"taskTitle": "Implement Basic Task Operations",
|
||||||
"complexityScore": 9,
|
"complexityScore": 8,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Break down the task operations into subtasks including listing, creating, updating, deleting, status changes, dependency management, and priority handling.",
|
"expansionPrompt": "Break down the implementation of basic task operations into subtasks covering CRUD operations, status management, dependency handling, and priority management. Each subtask should detail the specific operations, validation requirements, and error cases to handle.",
|
||||||
"reasoning": "This task requires implementing a wide range of operations, each with its own logic and dependencies, increasing the complexity."
|
"reasoning": "This task encompasses multiple operations (create, read, update, delete) along with status changes, dependency management, and priority handling. It represents high complexity due to the breadth of functionality and the need to ensure data integrity across operations."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 4,
|
"taskId": 4,
|
||||||
"taskTitle": "Create Task File Generation System",
|
"taskTitle": "Create Task File Generation System",
|
||||||
"complexityScore": 7,
|
"complexityScore": 7,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Divide the file generation system into subtasks such as template creation, file generation, synchronization, file naming, and update handling.",
|
"expansionPrompt": "Divide the task file generation system into subtasks covering template creation, file generation logic, bi-directional synchronization, and file organization. Each subtask should specify the technical approach, edge cases to handle, and integration points with the task data structure.",
|
||||||
"reasoning": "The task involves creating a system that generates and synchronizes files, requiring careful handling of templates and updates."
|
"reasoning": "Implementing file generation with bi-directional synchronization presents significant complexity due to the need to maintain consistency between individual files and the central tasks.json. The system must handle updates in either direction and resolve potential conflicts."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 5,
|
"taskId": 5,
|
||||||
"taskTitle": "Integrate Anthropic Claude API",
|
"taskTitle": "Integrate Anthropic Claude API",
|
||||||
"complexityScore": 8,
|
"complexityScore": 6,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Break down the API integration into subtasks including authentication, prompt templates, response handling, error management, token tracking, and model configuration.",
|
"expansionPrompt": "Break down the Claude API integration into subtasks covering authentication setup, prompt template creation, response handling, and error management with retries. Each subtask should detail the specific implementation approach, including security considerations and performance optimizations.",
|
||||||
"reasoning": "Integrating an external API involves multiple steps from authentication to response handling, each adding to the complexity."
|
"reasoning": "Integrating with the Claude API involves setting up authentication, creating effective prompts, and handling responses and errors. The complexity is moderate, focusing on establishing a reliable connection to the external service with proper error handling and retry logic."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 6,
|
"taskId": 6,
|
||||||
"taskTitle": "Build PRD Parsing System",
|
"taskTitle": "Build PRD Parsing System",
|
||||||
"complexityScore": 9,
|
"complexityScore": 8,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Divide the PRD parsing system into subtasks such as file reading, prompt engineering, task conversion, dependency inference, priority assignment, and chunking.",
|
"expansionPrompt": "Divide the PRD parsing system into subtasks covering file reading, prompt engineering, content-to-task conversion, dependency inference, priority assignment, and handling large documents. Each subtask should specify the AI interaction approach, data transformation steps, and validation requirements.",
|
||||||
"reasoning": "Parsing PRDs and converting them into tasks requires handling various complexities including dependency inference and priority assignment."
|
"reasoning": "Parsing PRDs into structured tasks requires sophisticated prompt engineering and intelligent processing of unstructured text. The complexity is high due to the need to accurately extract tasks, infer dependencies, and handle potentially large documents with varying formats."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 7,
|
"taskId": 7,
|
||||||
"taskTitle": "Implement Task Expansion with Claude",
|
"taskTitle": "Implement Task Expansion with Claude",
|
||||||
"complexityScore": 7,
|
"complexityScore": 7,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Break down the task expansion into subtasks including prompt creation, workflow implementation, context-aware expansion, relationship management, subtask specification, and regeneration.",
|
"expansionPrompt": "Break down the task expansion functionality into subtasks covering prompt creation for subtask generation, expansion workflow implementation, parent-child relationship management, and regeneration mechanisms. Each subtask should detail the AI interaction patterns, data structures, and user experience considerations.",
|
||||||
"reasoning": "Expanding tasks into subtasks using AI involves creating prompts and managing relationships, adding to the complexity."
|
"reasoning": "Task expansion involves complex AI interactions to generate meaningful subtasks and manage their relationships with parent tasks. The complexity comes from creating effective prompts that produce useful subtasks and implementing a smooth workflow for users to generate and refine these subtasks."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 8,
|
"taskId": 8,
|
||||||
"taskTitle": "Develop Implementation Drift Handling",
|
"taskTitle": "Develop Implementation Drift Handling",
|
||||||
"complexityScore": 8,
|
"complexityScore": 9,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Divide the drift handling into subtasks including task updates, rewriting, dependency chain updates, completed work preservation, and update analysis.",
|
"expansionPrompt": "Divide the implementation drift handling into subtasks covering change detection, task rewriting based on new context, dependency chain updates, work preservation, and update suggestion analysis. Each subtask should specify the algorithms, heuristics, and AI prompts needed to effectively manage implementation changes.",
|
||||||
"reasoning": "Handling implementation drift requires updating tasks and dependencies while preserving completed work, increasing complexity."
|
"reasoning": "This task involves the complex challenge of updating future tasks based on changes in implementation. It requires sophisticated analysis of completed work, understanding how it affects pending tasks, and intelligently updating those tasks while preserving dependencies. This represents high complexity due to the need for context-aware AI reasoning."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 9,
|
"taskId": 9,
|
||||||
"taskTitle": "Integrate Perplexity API",
|
"taskTitle": "Integrate Perplexity API",
|
||||||
"complexityScore": 7,
|
"complexityScore": 5,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 3,
|
||||||
"expansionPrompt": "Break down the API integration into subtasks including authentication, prompt templates, response handling, fallback logic, quality comparison, and model selection.",
|
"expansionPrompt": "Break down the Perplexity API integration into subtasks covering authentication setup, research-oriented prompt creation, response handling, and fallback mechanisms. Each subtask should detail the implementation approach, integration with existing systems, and quality comparison metrics.",
|
||||||
"reasoning": "Integrating another external API involves similar complexities as the Claude API integration, including authentication and response handling."
|
"reasoning": "Similar to the Claude integration but slightly less complex, this task focuses on connecting to the Perplexity API for research capabilities. The complexity is moderate, involving API authentication, prompt templates, and response handling with fallback mechanisms to Claude."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 10,
|
"taskId": 10,
|
||||||
"taskTitle": "Create Research-Backed Subtask Generation",
|
"taskTitle": "Create Research-Backed Subtask Generation",
|
||||||
"complexityScore": 8,
|
"complexityScore": 7,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Divide the research-backed generation into subtasks including prompt creation, context enrichment, domain knowledge incorporation, detailed generation, and reference inclusion.",
|
"expansionPrompt": "Divide the research-backed subtask generation into subtasks covering domain-specific prompt creation, context enrichment from research, knowledge incorporation, and detailed subtask generation. Each subtask should specify the approach for leveraging research data and integrating it into the generation process.",
|
||||||
"reasoning": "Enhancing subtask generation with research requires handling domain-specific knowledge and context enrichment, adding complexity."
|
"reasoning": "This task builds on previous work to enhance subtask generation with research capabilities. The complexity comes from effectively incorporating research results into the generation process and creating domain-specific prompts that produce high-quality, detailed subtasks with best practices."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 11,
|
"taskId": 11,
|
||||||
"taskTitle": "Implement Batch Operations",
|
"taskTitle": "Implement Batch Operations",
|
||||||
"complexityScore": 7,
|
"complexityScore": 6,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Break down the batch operations into subtasks including status updates, subtask generation, task filtering, dependency management, prioritization, and command creation.",
|
"expansionPrompt": "Break down the batch operations functionality into subtasks covering multi-task status updates, bulk subtask generation, task filtering/querying, and batch prioritization. Each subtask should detail the command interface, implementation approach, and performance considerations for handling multiple tasks.",
|
||||||
"reasoning": "Implementing batch operations involves handling multiple tasks simultaneously, each with its own set of operations."
|
"reasoning": "Implementing batch operations requires extending existing functionality to work with multiple tasks simultaneously. The complexity is moderate, focusing on efficient processing of task sets, filtering capabilities, and maintaining data consistency across bulk operations."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 12,
|
"taskId": 12,
|
||||||
"taskTitle": "Develop Project Initialization System",
|
"taskTitle": "Develop Project Initialization System",
|
||||||
"complexityScore": 8,
|
"complexityScore": 6,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Divide the project initialization into subtasks including templating, setup wizard, environment configuration, directory structure, example tasks, and default configuration.",
|
"expansionPrompt": "Divide the project initialization system into subtasks covering project templating, interactive setup wizard, environment configuration, directory structure creation, and example generation. Each subtask should specify the user interaction flow, template design, and integration with existing components.",
|
||||||
"reasoning": "Creating a project initialization system involves setting up multiple components and configurations, increasing complexity."
|
"reasoning": "Creating a project initialization system involves setting up templates, an interactive wizard, and generating initial files and directories. The complexity is moderate, focusing on providing a smooth setup experience for new projects with appropriate defaults and configuration."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 13,
|
"taskId": 13,
|
||||||
"taskTitle": "Create Cursor Rules Implementation",
|
"taskTitle": "Create Cursor Rules Implementation",
|
||||||
"complexityScore": 7,
|
"complexityScore": 5,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 3,
|
||||||
"expansionPrompt": "Break down the Cursor rules implementation into subtasks including documentation creation, rule implementation, directory setup, and integration documentation.",
|
"expansionPrompt": "Break down the Cursor rules implementation into subtasks covering documentation creation (dev_workflow.mdc, cursor_rules.mdc, self_improve.mdc), directory structure setup, and integration documentation. Each subtask should detail the specific content to include and how it enables effective AI interaction.",
|
||||||
"reasoning": "Implementing Cursor rules involves creating documentation and setting up directory structures, adding to the complexity."
|
"reasoning": "This task focuses on creating documentation and rules for Cursor AI integration. The complexity is moderate, involving the creation of structured documentation files that define how AI should interact with the system and setting up the appropriate directory structure."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 14,
|
"taskId": 14,
|
||||||
"taskTitle": "Develop Agent Workflow Guidelines",
|
"taskTitle": "Develop Agent Workflow Guidelines",
|
||||||
"complexityScore": 7,
|
"complexityScore": 5,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 3,
|
||||||
"expansionPrompt": "Divide the agent workflow guidelines into subtasks including task discovery, selection, implementation, verification, prioritization, and dependency handling.",
|
"expansionPrompt": "Divide the agent workflow guidelines into subtasks covering task discovery documentation, selection guidelines, implementation guidance, verification procedures, and prioritization rules. Each subtask should specify the specific guidance to provide and how it enables effective agent workflows.",
|
||||||
"reasoning": "Creating guidelines for AI agents involves defining workflows and handling dependencies, increasing complexity."
|
"reasoning": "Creating comprehensive guidelines for AI agents involves documenting workflows, selection criteria, and implementation guidance. The complexity is moderate, focusing on clear documentation that helps agents interact effectively with the task system."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 15,
|
"taskId": 15,
|
||||||
"taskTitle": "Implement Agent Command Integration",
|
"taskTitle": "Optimize Agent Integration with Cursor and dev.js Commands",
|
||||||
"complexityScore": 8,
|
"complexityScore": 6,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Break down the agent command integration into subtasks including command syntax, example interactions, response patterns, context management, special flags, and output interpretation.",
|
"expansionPrompt": "Break down the agent integration optimization into subtasks covering existing pattern documentation, Cursor-dev.js command integration enhancement, workflow documentation improvement, and feature additions. Each subtask should specify the specific improvements to make and how they enhance agent interaction.",
|
||||||
"reasoning": "Integrating commands for AI agents involves handling syntax, responses, and context, adding to the complexity."
|
"reasoning": "This task involves enhancing and documenting existing agent interaction patterns with Cursor and dev.js commands. The complexity is moderate, focusing on improving integration between different components and ensuring agents can effectively utilize the system's capabilities."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 16,
|
"taskId": 16,
|
||||||
"taskTitle": "Create Configuration Management System",
|
"taskTitle": "Create Configuration Management System",
|
||||||
"complexityScore": 8,
|
"complexityScore": 6,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 4,
|
||||||
"expansionPrompt": "Divide the configuration management into subtasks including environment handling, .env support, validation, defaults, template creation, documentation, and API key security.",
|
"expansionPrompt": "Divide the configuration management system into subtasks covering environment variable handling, .env file support, configuration validation, defaults with overrides, and secure API key handling. Each subtask should specify the implementation approach, security considerations, and user experience for configuration.",
|
||||||
"reasoning": "Implementing a robust configuration system involves handling environment variables, validation, and security, increasing complexity."
|
"reasoning": "Implementing robust configuration management involves handling environment variables, .env files, validation, and secure storage of sensitive information. The complexity is moderate, focusing on creating a flexible system that works across different environments with appropriate security measures."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 17,
|
"taskId": 17,
|
||||||
"taskTitle": "Implement Comprehensive Logging System",
|
"taskTitle": "Implement Comprehensive Logging System",
|
||||||
"complexityScore": 7,
|
"complexityScore": 5,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 3,
|
||||||
"expansionPrompt": "Break down the logging system into subtasks including log levels, output destinations, command logging, API logging, error tracking, metrics, and file rotation.",
|
"expansionPrompt": "Break down the logging system implementation into subtasks covering log level configuration, output destination management, specialized logging (commands, APIs, errors), and performance metrics. Each subtask should detail the implementation approach, configuration options, and integration with existing components.",
|
||||||
"reasoning": "Creating a logging system involves implementing multiple log levels and destinations, adding to the complexity."
|
"reasoning": "Creating a comprehensive logging system involves implementing multiple log levels, configurable destinations, and specialized logging for different components. The complexity is moderate, focusing on providing useful information for debugging and monitoring while maintaining performance."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 18,
|
"taskId": 18,
|
||||||
"taskTitle": "Create Comprehensive User Documentation",
|
"taskTitle": "Create Comprehensive User Documentation",
|
||||||
"complexityScore": 8,
|
"complexityScore": 7,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Divide the user documentation into subtasks including README creation, command reference, configuration guide, examples, troubleshooting, API documentation, and best practices.",
|
"expansionPrompt": "Divide the user documentation creation into subtasks covering README with installation instructions, command reference, configuration guide, example workflows, troubleshooting guides, and advanced usage. Each subtask should specify the content to include, format, and organization to ensure comprehensive coverage.",
|
||||||
"reasoning": "Developing comprehensive documentation involves covering multiple aspects of the system, increasing complexity."
|
"reasoning": "Creating comprehensive documentation requires covering installation, usage, configuration, examples, and troubleshooting across multiple components. The complexity is moderate to high due to the breadth of functionality to document and the need to make it accessible to different user levels."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 19,
|
"taskId": 19,
|
||||||
"taskTitle": "Implement Error Handling and Recovery",
|
"taskTitle": "Implement Error Handling and Recovery",
|
||||||
"complexityScore": 8,
|
"complexityScore": 8,
|
||||||
"recommendedSubtasks": 6,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Break down the implementation of error handling and recovery into 6 subtasks, focusing on different aspects like message formatting, API handling, file system recovery, data validation, command errors, and system state recovery. For each subtask, specify the key components to implement and any specific techniques or best practices to consider.",
|
"expansionPrompt": "Break down the error handling implementation into subtasks covering consistent error formatting, helpful error messages, API error handling with retries, file system error recovery, validation errors, and system state recovery. Each subtask should detail the specific error types to handle, recovery strategies, and user communication approach.",
|
||||||
"reasoning": "High complexity due to system-wide implementation, multiple error types, and recovery mechanisms. Requires careful design and integration across various system components."
|
"reasoning": "Implementing robust error handling across the entire system represents high complexity due to the variety of error types, the need for meaningful messages, and the implementation of recovery mechanisms. This task is critical for system reliability and user experience."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskId": 20,
|
"taskId": 20,
|
||||||
"taskTitle": "Create Token Usage Tracking and Cost Management",
|
"taskTitle": "Create Token Usage Tracking and Cost Management",
|
||||||
"complexityScore": 7,
|
"complexityScore": 7,
|
||||||
|
"recommendedSubtasks": 4,
|
||||||
|
"expansionPrompt": "Divide the token tracking and cost management into subtasks covering usage tracking implementation, configurable limits, reporting features, cost estimation, caching for optimization, and usage alerts. Each subtask should specify the implementation approach, data storage, and user interface for monitoring and managing usage.",
|
||||||
|
"reasoning": "Implementing token usage tracking involves monitoring API calls, calculating costs, implementing limits, and optimizing usage through caching. The complexity is moderate to high, focusing on providing users with visibility into their API consumption and tools to manage costs."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": 21,
|
||||||
|
"taskTitle": "Refactor dev.js into Modular Components",
|
||||||
|
"complexityScore": 8,
|
||||||
"recommendedSubtasks": 5,
|
"recommendedSubtasks": 5,
|
||||||
"expansionPrompt": "Divide the token usage tracking and cost management system into 5 subtasks, covering usage tracking implementation, limit configuration, reporting and cost estimation, caching and optimization, and alert system development. For each subtask, outline the main features to implement and any key considerations for effective integration with the existing system.",
|
"expansionPrompt": "Break down the refactoring of dev.js into subtasks covering module design (commands.js, ai-services.js, task-manager.js, ui.js, utils.js), entry point restructuring, dependency management, error handling standardization, and documentation. Each subtask should detail the specific code to extract, interfaces to define, and integration points between modules.",
|
||||||
"reasoning": "Moderate to high complexity due to the need for accurate tracking, optimization strategies, and integration with existing API systems. Involves both data processing and user-facing features."
|
"reasoning": "Refactoring a monolithic file into modular components represents high complexity due to the need to identify appropriate boundaries, manage dependencies between modules, and ensure all functionality is preserved. This requires deep understanding of the existing codebase and careful restructuring."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": 22,
|
||||||
|
"taskTitle": "Create Comprehensive Test Suite for Task Master CLI",
|
||||||
|
"complexityScore": 9,
|
||||||
|
"recommendedSubtasks": 5,
|
||||||
|
"expansionPrompt": "Divide the test suite creation into subtasks covering unit test implementation, integration test development, end-to-end test creation, mocking setup, and CI integration. Each subtask should specify the testing approach, coverage goals, test data preparation, and specific functionality to test.",
|
||||||
|
"reasoning": "Developing a comprehensive test suite represents high complexity due to the need to cover unit, integration, and end-to-end tests across all functionality, implement appropriate mocking, and ensure good test coverage. This requires significant test engineering and understanding of the entire system."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": 23,
|
||||||
|
"taskTitle": "Implement MCP (Model Context Protocol) Server Functionality for Task Master",
|
||||||
|
"complexityScore": 9,
|
||||||
|
"recommendedSubtasks": 5,
|
||||||
|
"expansionPrompt": "Break down the MCP server implementation into subtasks covering core server module creation, endpoint implementation (/context, /models, /execute), context management system, authentication mechanisms, and performance optimization. Each subtask should detail the API design, data structures, and integration with existing Task Master functionality.",
|
||||||
|
"reasoning": "Implementing an MCP server represents high complexity due to the need to create a RESTful API with multiple endpoints, manage context data efficiently, handle authentication, and ensure compatibility with the MCP specification. This requires significant API design and server-side development work."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": 24,
|
||||||
|
"taskTitle": "Implement AI-Powered Test Generation Command",
|
||||||
|
"complexityScore": 7,
|
||||||
|
"recommendedSubtasks": 4,
|
||||||
|
"expansionPrompt": "Divide the test generation command implementation into subtasks covering command structure and parameter handling, task analysis logic, AI prompt construction, and test file generation. Each subtask should specify the implementation approach, AI interaction pattern, and output formatting requirements.",
|
||||||
|
"reasoning": "Creating an AI-powered test generation command involves analyzing tasks, constructing effective prompts, and generating well-formatted test files. The complexity is moderate to high, focusing on leveraging AI to produce useful tests based on task descriptions and subtasks."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1414,7 +1414,7 @@
|
|||||||
"description": "Extend Task Master to function as an MCP server, allowing it to provide context management services to other applications following the Model Context Protocol specification.",
|
"description": "Extend Task Master to function as an MCP server, allowing it to provide context management services to other applications following the Model Context Protocol specification.",
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"22"
|
22
|
||||||
],
|
],
|
||||||
"priority": "medium",
|
"priority": "medium",
|
||||||
"details": "This task involves implementing the Model Context Protocol server capabilities within Task Master. The implementation should:\n\n1. Create a new module `mcp-server.js` that implements the core MCP server functionality\n2. Implement the required MCP endpoints:\n - `/context` - For retrieving and updating context\n - `/models` - For listing available models\n - `/execute` - For executing operations with context\n3. Develop a context management system that can:\n - Store and retrieve context data efficiently\n - Handle context windowing and truncation when limits are reached\n - Support context metadata and tagging\n4. Add authentication and authorization mechanisms for MCP clients\n5. Implement proper error handling and response formatting according to MCP specifications\n6. Create configuration options in Task Master to enable/disable the MCP server functionality\n7. Add documentation for how to use Task Master as an MCP server\n8. Ensure the implementation is compatible with existing MCP clients\n9. Optimize for performance, especially for context retrieval operations\n10. Add logging for MCP server operations\n\nThe implementation should follow RESTful API design principles and should be able to handle concurrent requests from multiple clients.",
|
"details": "This task involves implementing the Model Context Protocol server capabilities within Task Master. The implementation should:\n\n1. Create a new module `mcp-server.js` that implements the core MCP server functionality\n2. Implement the required MCP endpoints:\n - `/context` - For retrieving and updating context\n - `/models` - For listing available models\n - `/execute` - For executing operations with context\n3. Develop a context management system that can:\n - Store and retrieve context data efficiently\n - Handle context windowing and truncation when limits are reached\n - Support context metadata and tagging\n4. Add authentication and authorization mechanisms for MCP clients\n5. Implement proper error handling and response formatting according to MCP specifications\n6. Create configuration options in Task Master to enable/disable the MCP server functionality\n7. Add documentation for how to use Task Master as an MCP server\n8. Ensure the implementation is compatible with existing MCP clients\n9. Optimize for performance, especially for context retrieval operations\n10. Add logging for MCP server operations\n\nThe implementation should follow RESTful API design principles and should be able to handle concurrent requests from multiple clients.",
|
||||||
@@ -1426,7 +1426,7 @@
|
|||||||
"description": "Create a new 'generate-test' command that leverages AI to automatically produce Jest test files for tasks based on their descriptions and subtasks.",
|
"description": "Create a new 'generate-test' command that leverages AI to automatically produce Jest test files for tasks based on their descriptions and subtasks.",
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"22"
|
22
|
||||||
],
|
],
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"details": "Implement a new command in the Task Master CLI that generates comprehensive Jest test files for tasks. The command should be callable as 'task-master generate-test --id=1' and should:\n\n1. Accept a task ID parameter to identify which task to generate tests for\n2. Retrieve the task and its subtasks from the task store\n3. Analyze the task description, details, and subtasks to understand implementation requirements\n4. Construct an appropriate prompt for an AI service (e.g., OpenAI API) that requests generation of Jest tests\n5. Process the AI response to create a well-formatted test file named 'task_XXX.test.js' where XXX is the zero-padded task ID\n6. Include appropriate test cases that cover the main functionality described in the task\n7. Generate mocks for external dependencies identified in the task description\n8. Create assertions that validate the expected behavior\n9. Handle both parent tasks and subtasks appropriately (for subtasks, name the file 'task_XXX_YYY.test.js' where YYY is the subtask ID)\n10. Include error handling for API failures, invalid task IDs, etc.\n11. Add appropriate documentation for the command in the help system\n\nThe implementation should utilize the existing AI service integration in the codebase and maintain consistency with the current command structure and error handling patterns.",
|
"details": "Implement a new command in the Task Master CLI that generates comprehensive Jest test files for tasks. The command should be callable as 'task-master generate-test --id=1' and should:\n\n1. Accept a task ID parameter to identify which task to generate tests for\n2. Retrieve the task and its subtasks from the task store\n3. Analyze the task description, details, and subtasks to understand implementation requirements\n4. Construct an appropriate prompt for an AI service (e.g., OpenAI API) that requests generation of Jest tests\n5. Process the AI response to create a well-formatted test file named 'task_XXX.test.js' where XXX is the zero-padded task ID\n6. Include appropriate test cases that cover the main functionality described in the task\n7. Generate mocks for external dependencies identified in the task description\n8. Create assertions that validate the expected behavior\n9. Handle both parent tasks and subtasks appropriately (for subtasks, name the file 'task_XXX_YYY.test.js' where YYY is the subtask ID)\n10. Include error handling for API failures, invalid task IDs, etc.\n11. Add appropriate documentation for the command in the help system\n\nThe implementation should utilize the existing AI service integration in the codebase and maintain consistency with the current command structure and error handling patterns.",
|
||||||
|
|||||||
@@ -150,4 +150,36 @@ describe('Task Manager Module', () => {
|
|||||||
expect(nextTask).toBeNull();
|
expect(nextTask).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Skipped tests for analyzeTaskComplexity
|
||||||
|
describe.skip('analyzeTaskComplexity function', () => {
|
||||||
|
// These tests are skipped because they require complex mocking
|
||||||
|
// but document what should be tested
|
||||||
|
|
||||||
|
test('should handle valid JSON response from LLM', async () => {
|
||||||
|
// This test would verify that:
|
||||||
|
// 1. The function properly calls the AI model
|
||||||
|
// 2. It correctly parses a valid JSON response
|
||||||
|
// 3. It generates a properly formatted complexity report
|
||||||
|
// 4. The report includes all analyzed tasks with their complexity scores
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle and fix malformed JSON with unterminated strings', async () => {
|
||||||
|
// This test would verify that:
|
||||||
|
// 1. The function can handle JSON with unterminated strings
|
||||||
|
// 2. It applies regex fixes to repair the malformed JSON
|
||||||
|
// 3. It still produces a valid report despite receiving bad JSON
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle missing tasks in the response', async () => {
|
||||||
|
// This test would verify that:
|
||||||
|
// 1. When the AI response is missing some tasks
|
||||||
|
// 2. The function detects the missing tasks
|
||||||
|
// 3. It attempts to analyze just those missing tasks
|
||||||
|
// 4. The final report includes all tasks that could be analyzed
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user