feat: add --compact flag for minimal task list output (#1054)

* feat: add --compact flag for minimal task list output

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Ladi
2025-08-11 18:35:23 +02:00
committed by GitHub
parent 30ca144231
commit 782728ff95
7 changed files with 343 additions and 13 deletions

View File

@@ -294,6 +294,11 @@ function listTasks(
});
}
// For compact output, return minimal one-line format
if (outputFormat === 'compact') {
return renderCompactOutput(filteredTasks, withSubtasks);
}
// ... existing code for text output ...
// Calculate status breakdowns as percentages of total
@@ -962,4 +967,98 @@ function generateMarkdownOutput(data, filteredTasks, stats) {
return markdown;
}
/**
* Format dependencies for compact output with truncation and coloring
* @param {Array} dependencies - Array of dependency IDs
* @returns {string} - Formatted dependency string with arrow prefix
*/
function formatCompactDependencies(dependencies) {
if (!dependencies || dependencies.length === 0) {
return '';
}
if (dependencies.length > 5) {
const visible = dependencies.slice(0, 5).join(',');
const remaining = dependencies.length - 5;
return `${chalk.cyan(visible)}${chalk.gray('... (+' + remaining + ' more)')}`;
} else {
return `${chalk.cyan(dependencies.join(','))}`;
}
}
/**
* Format a single task in compact one-line format
* @param {Object} task - Task object
* @param {number} maxTitleLength - Maximum title length before truncation
* @returns {string} - Formatted task line
*/
function formatCompactTask(task, maxTitleLength = 50) {
const status = task.status || 'pending';
const priority = task.priority || 'medium';
const title = truncate(task.title || 'Untitled', maxTitleLength);
// Use colored status from existing function
const coloredStatus = getStatusWithColor(status, true);
// Color priority based on level
const priorityColors = {
high: chalk.red,
medium: chalk.yellow,
low: chalk.gray
};
const priorityColor = priorityColors[priority] || chalk.white;
// Format dependencies using shared helper
const depsText = formatCompactDependencies(task.dependencies);
return `${chalk.cyan(task.id)} ${coloredStatus} ${chalk.white(title)} ${priorityColor('(' + priority + ')')}${depsText}`;
}
/**
* Format a subtask in compact format with indentation
* @param {Object} subtask - Subtask object
* @param {string|number} parentId - Parent task ID
* @param {number} maxTitleLength - Maximum title length before truncation
* @returns {string} - Formatted subtask line
*/
function formatCompactSubtask(subtask, parentId, maxTitleLength = 47) {
const status = subtask.status || 'pending';
const title = truncate(subtask.title || 'Untitled', maxTitleLength);
// Use colored status from existing function
const coloredStatus = getStatusWithColor(status, true);
// Format dependencies using shared helper
const depsText = formatCompactDependencies(subtask.dependencies);
return ` ${chalk.cyan(parentId + '.' + subtask.id)} ${coloredStatus} ${chalk.dim(title)}${depsText}`;
}
/**
* Render complete compact output
* @param {Array} filteredTasks - Tasks to display
* @param {boolean} withSubtasks - Whether to include subtasks
* @returns {void} - Outputs directly to console
*/
function renderCompactOutput(filteredTasks, withSubtasks) {
if (filteredTasks.length === 0) {
console.log('No tasks found');
return;
}
const output = [];
filteredTasks.forEach((task) => {
output.push(formatCompactTask(task));
if (withSubtasks && task.subtasks && task.subtasks.length > 0) {
task.subtasks.forEach((subtask) => {
output.push(formatCompactSubtask(subtask, task.id));
});
}
});
console.log(output.join('\n'));
}
export default listTasks;