fix merge conflicts to prep for merge with branch next
- Enhance E2E testing and LLM analysis report and: - Add --analyze-log flag to run_e2e.sh to re-run LLM analysis on existing logs. - Add test:e2e and analyze-log scripts to package.json for easier execution. - Correct display errors and dependency validation output: - Update chalk usage in add-task.js to use bracket notation (chalk[color]) compatible with v5, resolving 'chalk.keyword is not a function' error. - Modify fix-dependencies command output to show red failure box with issue count instead of green success box when validation fails. - Refactor interactive model setup: - Verify inclusion of 'No change' option during interactive model setup flow (task-master models --setup). - Update model definitions: - Add max_tokens field for gpt-4o in supported-models.json. - Remove unused scripts: - Delete prepare-package.js and rule-transformer.test.js. Release candidate
This commit is contained in:
@@ -179,18 +179,20 @@ async function addDependency(tasksPath, taskId, dependencyId) {
|
||||
);
|
||||
|
||||
// Display a more visually appealing success message
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.green(`Successfully added dependency:\n\n`) +
|
||||
`Task ${chalk.bold(formattedTaskId)} now depends on ${chalk.bold(formattedDependencyId)}`,
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: 'green',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 }
|
||||
}
|
||||
)
|
||||
);
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.green(`Successfully added dependency:\n\n`) +
|
||||
`Task ${chalk.bold(formattedTaskId)} now depends on ${chalk.bold(formattedDependencyId)}`,
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: 'green',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 }
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Generate updated task files
|
||||
await generateTaskFiles(tasksPath, 'tasks');
|
||||
@@ -353,11 +355,13 @@ function isCircularDependency(tasks, taskId, chain = []) {
|
||||
|
||||
// Find the task or subtask
|
||||
let task = null;
|
||||
let parentIdForSubtask = null;
|
||||
|
||||
// Check if this is a subtask reference (e.g., "1.2")
|
||||
if (taskIdStr.includes('.')) {
|
||||
const [parentId, subtaskId] = taskIdStr.split('.').map(Number);
|
||||
const parentTask = tasks.find((t) => t.id === parentId);
|
||||
parentIdForSubtask = parentId; // Store parent ID if it's a subtask
|
||||
|
||||
if (parentTask && parentTask.subtasks) {
|
||||
task = parentTask.subtasks.find((st) => st.id === subtaskId);
|
||||
@@ -377,10 +381,18 @@ function isCircularDependency(tasks, taskId, chain = []) {
|
||||
}
|
||||
|
||||
// Check each dependency recursively
|
||||
const newChain = [...chain, taskId];
|
||||
return task.dependencies.some((depId) =>
|
||||
isCircularDependency(tasks, depId, newChain)
|
||||
);
|
||||
const newChain = [...chain, taskIdStr]; // Use taskIdStr for consistency
|
||||
return task.dependencies.some((depId) => {
|
||||
let normalizedDepId = String(depId);
|
||||
// Normalize relative subtask dependencies
|
||||
if (typeof depId === 'number' && parentIdForSubtask !== null) {
|
||||
// If the current task is a subtask AND the dependency is a number,
|
||||
// assume it refers to a sibling subtask.
|
||||
normalizedDepId = `${parentIdForSubtask}.${depId}`;
|
||||
}
|
||||
// Pass the normalized ID to the recursive call
|
||||
return isCircularDependency(tasks, normalizedDepId, newChain);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,118 +591,43 @@ async function validateDependenciesCommand(tasksPath, options = {}) {
|
||||
`Analyzing dependencies for ${taskCount} tasks and ${subtaskCount} subtasks...`
|
||||
);
|
||||
|
||||
// Track validation statistics
|
||||
const stats = {
|
||||
nonExistentDependenciesRemoved: 0,
|
||||
selfDependenciesRemoved: 0,
|
||||
tasksFixed: 0,
|
||||
subtasksFixed: 0
|
||||
};
|
||||
|
||||
// Create a custom logger instead of reassigning the imported log function
|
||||
const warnings = [];
|
||||
const customLogger = function (level, ...args) {
|
||||
if (level === 'warn') {
|
||||
warnings.push(args.join(' '));
|
||||
|
||||
// Count the type of fix based on the warning message
|
||||
const msg = args.join(' ');
|
||||
if (msg.includes('self-dependency')) {
|
||||
stats.selfDependenciesRemoved++;
|
||||
} else if (msg.includes('invalid')) {
|
||||
stats.nonExistentDependenciesRemoved++;
|
||||
}
|
||||
|
||||
// Count if it's a task or subtask being fixed
|
||||
if (msg.includes('from subtask')) {
|
||||
stats.subtasksFixed++;
|
||||
} else if (msg.includes('from task')) {
|
||||
stats.tasksFixed++;
|
||||
}
|
||||
}
|
||||
// Call the original log function
|
||||
return log(level, ...args);
|
||||
};
|
||||
|
||||
// Run validation with custom logger
|
||||
try {
|
||||
// Temporarily save validateTaskDependencies function with normal log
|
||||
const originalValidateTaskDependencies = validateTaskDependencies;
|
||||
// Directly call the validation function
|
||||
const validationResult = validateTaskDependencies(data.tasks);
|
||||
|
||||
// Create patched version that uses customLogger
|
||||
const patchedValidateTaskDependencies = (tasks, tasksPath) => {
|
||||
// Temporarily redirect log calls in this scope
|
||||
const originalLog = log;
|
||||
const logProxy = function (...args) {
|
||||
return customLogger(...args);
|
||||
};
|
||||
if (!validationResult.valid) {
|
||||
log(
|
||||
'error',
|
||||
`Dependency validation failed. Found ${validationResult.issues.length} issue(s):`
|
||||
);
|
||||
validationResult.issues.forEach((issue) => {
|
||||
let errorMsg = ` [${issue.type.toUpperCase()}] Task ${issue.taskId}: ${issue.message}`;
|
||||
if (issue.dependencyId) {
|
||||
errorMsg += ` (Dependency: ${issue.dependencyId})`;
|
||||
}
|
||||
log('error', errorMsg); // Log each issue as an error
|
||||
});
|
||||
|
||||
// Call the original function in a context where log calls are intercepted
|
||||
const result = (() => {
|
||||
// Use Function.prototype.bind to create a new function that has logProxy available
|
||||
// Pass isCircularDependency explicitly to make it available
|
||||
return Function(
|
||||
'tasks',
|
||||
'tasksPath',
|
||||
'log',
|
||||
'customLogger',
|
||||
'isCircularDependency',
|
||||
'taskExists',
|
||||
`return (${originalValidateTaskDependencies.toString()})(tasks, tasksPath);`
|
||||
)(
|
||||
tasks,
|
||||
tasksPath,
|
||||
logProxy,
|
||||
customLogger,
|
||||
isCircularDependency,
|
||||
taskExists
|
||||
);
|
||||
})();
|
||||
// Optionally exit if validation fails, depending on desired behavior
|
||||
// process.exit(1); // Uncomment if validation failure should stop the process
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const changesDetected = patchedValidateTaskDependencies(
|
||||
data.tasks,
|
||||
tasksPath
|
||||
);
|
||||
|
||||
// Create a detailed report
|
||||
if (changesDetected) {
|
||||
log('success', 'Invalid dependencies were removed from tasks.json');
|
||||
|
||||
// Show detailed stats in a nice box - only if not in silent mode
|
||||
// Display summary box even on failure, showing issues found
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.green(`Dependency Validation Results:\n\n`) +
|
||||
chalk.red(`Dependency Validation FAILED\n\n`) +
|
||||
`${chalk.cyan('Tasks checked:')} ${taskCount}\n` +
|
||||
`${chalk.cyan('Subtasks checked:')} ${subtaskCount}\n` +
|
||||
`${chalk.cyan('Non-existent dependencies removed:')} ${stats.nonExistentDependenciesRemoved}\n` +
|
||||
`${chalk.cyan('Self-dependencies removed:')} ${stats.selfDependenciesRemoved}\n` +
|
||||
`${chalk.cyan('Tasks fixed:')} ${stats.tasksFixed}\n` +
|
||||
`${chalk.cyan('Subtasks fixed:')} ${stats.subtasksFixed}`,
|
||||
`${chalk.red('Issues found:')} ${validationResult.issues.length}`, // Display count from result
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: 'green',
|
||||
borderColor: 'red',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1, bottom: 1 }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Show all warnings in a collapsible list if there are many
|
||||
if (warnings.length > 0) {
|
||||
console.log(chalk.yellow('\nDetailed fixes:'));
|
||||
warnings.forEach((warning) => {
|
||||
console.log(` ${warning}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Regenerate task files to reflect the changes
|
||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||
log('info', 'Task files regenerated to reflect dependency changes');
|
||||
} else {
|
||||
log(
|
||||
'success',
|
||||
|
||||
Reference in New Issue
Block a user