refactor: enhance add-task fuzzy search and fix duplicate banner display
- **Remove hardcoded category system** in add-task that always matched 'Task management' - **Eliminate arbitrary limits** in fuzzy search results (5→25 high relevance, 3→10 medium relevance, 8→20 detailed tasks) - **Improve semantic weighting** in Fuse.js search (details=3, description=2, title=1.5) for better relevance - **Fix duplicate banner issue** by removing console.clear() and redundant displayBanner() calls from UI functions - **Enhance context generation** to rely on semantic similarity rather than rigid pattern matching - **Preserve terminal history** to address GitHub issue #553 about eating terminal lines - **Remove displayBanner() calls** from: displayHelp, displayNextTask, displayTaskById, displayComplexityReport, set-task-status, clear-subtasks, dependency-manager functions The add-task system now provides truly relevant task context based on semantic similarity rather than arbitrary categories and limits, while maintaining a cleaner terminal experience. Changes span: add-task.js, ui.js, set-task-status.js, clear-subtasks.js, list-tasks.js, dependency-manager.js Closes #553
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"models": {
|
||||
"main": {
|
||||
"provider": "openrouter",
|
||||
"modelId": "qwen/qwen3-235b-a22b:free",
|
||||
"provider": "anthropic",
|
||||
"modelId": "claude-sonnet-4-20250514",
|
||||
"maxTokens": 50000,
|
||||
"temperature": 0.2
|
||||
},
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Task ID: 97
|
||||
# Title: Create Taskmaster Jingle Implementation
|
||||
# Status: pending
|
||||
# Dependencies: 95, 57, 3, 2
|
||||
# Priority: medium
|
||||
# Description: Develop a musical jingle system for Taskmaster that plays sound effects during key CLI interactions to enhance user experience.
|
||||
# Details:
|
||||
This task involves implementing a sound system that plays audio cues during Taskmaster CLI operations. Key implementation steps include:
|
||||
|
||||
1. Audio System Integration:
|
||||
- Research and select appropriate audio library compatible with Node.js CLI applications
|
||||
- Implement cross-platform audio playback (Windows, macOS, Linux)
|
||||
- Create sound configuration options in .taskmasterconfig
|
||||
|
||||
2. Jingle Design:
|
||||
- Define sound triggers for key events (task creation, completion, errors, etc.)
|
||||
- Create or source appropriate sound files (WAV/MP3 format)
|
||||
- Implement volume control and mute option in settings
|
||||
|
||||
3. CLI Integration:
|
||||
- Add sound playback to core CLI commands (init, create, update, delete)
|
||||
- Implement optional sound effects toggle via command line flags
|
||||
- Ensure audio playback doesn't interfere with CLI performance
|
||||
|
||||
4. Documentation:
|
||||
- Update user guide with sound configuration instructions
|
||||
- Add troubleshooting section for audio playback issues
|
||||
|
||||
# Test Strategy:
|
||||
1. Verify audio plays correctly during each supported CLI operation
|
||||
2. Test sound configuration options across different platforms
|
||||
3. Confirm volume control and mute functionality works as expected
|
||||
4. Validate that audio playback doesn't affect CLI performance
|
||||
5. Test edge cases (no audio hardware, invalid sound files, etc.)
|
||||
6. Ensure sound effects can be disabled via configuration and CLI flags
|
||||
@@ -5871,22 +5871,6 @@
|
||||
"parentTaskId": 96
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 97,
|
||||
"title": "Create Taskmaster Jingle Implementation",
|
||||
"description": "Develop a musical jingle system for Taskmaster that plays sound effects during key CLI interactions to enhance user experience.",
|
||||
"details": "This task involves implementing a sound system that plays audio cues during Taskmaster CLI operations. Key implementation steps include:\n\n1. Audio System Integration:\n - Research and select appropriate audio library compatible with Node.js CLI applications\n - Implement cross-platform audio playback (Windows, macOS, Linux)\n - Create sound configuration options in .taskmasterconfig\n\n2. Jingle Design:\n - Define sound triggers for key events (task creation, completion, errors, etc.)\n - Create or source appropriate sound files (WAV/MP3 format)\n - Implement volume control and mute option in settings\n\n3. CLI Integration:\n - Add sound playback to core CLI commands (init, create, update, delete)\n - Implement optional sound effects toggle via command line flags\n - Ensure audio playback doesn't interfere with CLI performance\n\n4. Documentation:\n - Update user guide with sound configuration instructions\n - Add troubleshooting section for audio playback issues",
|
||||
"testStrategy": "1. Verify audio plays correctly during each supported CLI operation\n2. Test sound configuration options across different platforms\n3. Confirm volume control and mute functionality works as expected\n4. Validate that audio playback doesn't affect CLI performance\n5. Test edge cases (no audio hardware, invalid sound files, etc.)\n6. Ensure sound effects can be disabled via configuration and CLI flags",
|
||||
"status": "pending",
|
||||
"dependencies": [
|
||||
95,
|
||||
57,
|
||||
3,
|
||||
2
|
||||
],
|
||||
"priority": "medium",
|
||||
"subtasks": []
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import boxen from 'boxen';
|
||||
import Table from 'cli-table3';
|
||||
import path from "path";
|
||||
import chalk from "chalk";
|
||||
import boxen from "boxen";
|
||||
import Table from "cli-table3";
|
||||
|
||||
import { log, readJSON, writeJSON, truncate, isSilentMode } from '../utils.js';
|
||||
import { displayBanner } from '../ui.js';
|
||||
import generateTaskFiles from './generate-task-files.js';
|
||||
import { log, readJSON, writeJSON, truncate, isSilentMode } from "../utils.js";
|
||||
import { displayBanner } from "../ui.js";
|
||||
import generateTaskFiles from "./generate-task-files.js";
|
||||
|
||||
/**
|
||||
* Clear subtasks from specified tasks
|
||||
@@ -13,140 +13,138 @@ import generateTaskFiles from './generate-task-files.js';
|
||||
* @param {string} taskIds - Task IDs to clear subtasks from
|
||||
*/
|
||||
function clearSubtasks(tasksPath, taskIds) {
|
||||
displayBanner();
|
||||
log("info", `Reading tasks from ${tasksPath}...`);
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
log("error", "No valid tasks found.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
log('info', `Reading tasks from ${tasksPath}...`);
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
log('error', 'No valid tasks found.');
|
||||
process.exit(1);
|
||||
}
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(chalk.white.bold("Clearing Subtasks"), {
|
||||
padding: 1,
|
||||
borderColor: "blue",
|
||||
borderStyle: "round",
|
||||
margin: { top: 1, bottom: 1 },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(chalk.white.bold('Clearing Subtasks'), {
|
||||
padding: 1,
|
||||
borderColor: 'blue',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1, bottom: 1 }
|
||||
})
|
||||
);
|
||||
}
|
||||
// Handle multiple task IDs (comma-separated)
|
||||
const taskIdArray = taskIds.split(",").map((id) => id.trim());
|
||||
let clearedCount = 0;
|
||||
|
||||
// Handle multiple task IDs (comma-separated)
|
||||
const taskIdArray = taskIds.split(',').map((id) => id.trim());
|
||||
let clearedCount = 0;
|
||||
// Create a summary table for the cleared subtasks
|
||||
const summaryTable = new Table({
|
||||
head: [
|
||||
chalk.cyan.bold("Task ID"),
|
||||
chalk.cyan.bold("Task Title"),
|
||||
chalk.cyan.bold("Subtasks Cleared"),
|
||||
],
|
||||
colWidths: [10, 50, 20],
|
||||
style: { head: [], border: [] },
|
||||
});
|
||||
|
||||
// Create a summary table for the cleared subtasks
|
||||
const summaryTable = new Table({
|
||||
head: [
|
||||
chalk.cyan.bold('Task ID'),
|
||||
chalk.cyan.bold('Task Title'),
|
||||
chalk.cyan.bold('Subtasks Cleared')
|
||||
],
|
||||
colWidths: [10, 50, 20],
|
||||
style: { head: [], border: [] }
|
||||
});
|
||||
taskIdArray.forEach((taskId) => {
|
||||
const id = parseInt(taskId, 10);
|
||||
if (isNaN(id)) {
|
||||
log("error", `Invalid task ID: ${taskId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
taskIdArray.forEach((taskId) => {
|
||||
const id = parseInt(taskId, 10);
|
||||
if (isNaN(id)) {
|
||||
log('error', `Invalid task ID: ${taskId}`);
|
||||
return;
|
||||
}
|
||||
const task = data.tasks.find((t) => t.id === id);
|
||||
if (!task) {
|
||||
log("error", `Task ${id} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
const task = data.tasks.find((t) => t.id === id);
|
||||
if (!task) {
|
||||
log('error', `Task ${id} not found`);
|
||||
return;
|
||||
}
|
||||
if (!task.subtasks || task.subtasks.length === 0) {
|
||||
log("info", `Task ${id} has no subtasks to clear`);
|
||||
summaryTable.push([
|
||||
id.toString(),
|
||||
truncate(task.title, 47),
|
||||
chalk.yellow("No subtasks"),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!task.subtasks || task.subtasks.length === 0) {
|
||||
log('info', `Task ${id} has no subtasks to clear`);
|
||||
summaryTable.push([
|
||||
id.toString(),
|
||||
truncate(task.title, 47),
|
||||
chalk.yellow('No subtasks')
|
||||
]);
|
||||
return;
|
||||
}
|
||||
const subtaskCount = task.subtasks.length;
|
||||
task.subtasks = [];
|
||||
clearedCount++;
|
||||
log("info", `Cleared ${subtaskCount} subtasks from task ${id}`);
|
||||
|
||||
const subtaskCount = task.subtasks.length;
|
||||
task.subtasks = [];
|
||||
clearedCount++;
|
||||
log('info', `Cleared ${subtaskCount} subtasks from task ${id}`);
|
||||
summaryTable.push([
|
||||
id.toString(),
|
||||
truncate(task.title, 47),
|
||||
chalk.green(`${subtaskCount} subtasks cleared`),
|
||||
]);
|
||||
});
|
||||
|
||||
summaryTable.push([
|
||||
id.toString(),
|
||||
truncate(task.title, 47),
|
||||
chalk.green(`${subtaskCount} subtasks cleared`)
|
||||
]);
|
||||
});
|
||||
if (clearedCount > 0) {
|
||||
writeJSON(tasksPath, data);
|
||||
|
||||
if (clearedCount > 0) {
|
||||
writeJSON(tasksPath, data);
|
||||
// Show summary table
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(chalk.white.bold("Subtask Clearing Summary:"), {
|
||||
padding: { left: 2, right: 2, top: 0, bottom: 0 },
|
||||
margin: { top: 1, bottom: 0 },
|
||||
borderColor: "blue",
|
||||
borderStyle: "round",
|
||||
})
|
||||
);
|
||||
console.log(summaryTable.toString());
|
||||
}
|
||||
|
||||
// Show summary table
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(chalk.white.bold('Subtask Clearing Summary:'), {
|
||||
padding: { left: 2, right: 2, top: 0, bottom: 0 },
|
||||
margin: { top: 1, bottom: 0 },
|
||||
borderColor: 'blue',
|
||||
borderStyle: 'round'
|
||||
})
|
||||
);
|
||||
console.log(summaryTable.toString());
|
||||
}
|
||||
// Regenerate task files to reflect changes
|
||||
log("info", "Regenerating task files...");
|
||||
generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||
|
||||
// Regenerate task files to reflect changes
|
||||
log('info', 'Regenerating task files...');
|
||||
generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||
// Success message
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.green(
|
||||
`Successfully cleared subtasks from ${chalk.bold(clearedCount)} task(s)`
|
||||
),
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: "green",
|
||||
borderStyle: "round",
|
||||
margin: { top: 1 },
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Success message
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.green(
|
||||
`Successfully cleared subtasks from ${chalk.bold(clearedCount)} task(s)`
|
||||
),
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: 'green',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Next steps suggestion
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold('Next Steps:') +
|
||||
'\n\n' +
|
||||
`${chalk.cyan('1.')} Run ${chalk.yellow('task-master expand --id=<id>')} to generate new subtasks\n` +
|
||||
`${chalk.cyan('2.')} Run ${chalk.yellow('task-master list --with-subtasks')} to verify changes`,
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: 'cyan',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 }
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(chalk.yellow('No subtasks were cleared'), {
|
||||
padding: 1,
|
||||
borderColor: 'yellow',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 }
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
// Next steps suggestion
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold("Next Steps:") +
|
||||
"\n\n" +
|
||||
`${chalk.cyan("1.")} Run ${chalk.yellow("task-master expand --id=<id>")} to generate new subtasks\n` +
|
||||
`${chalk.cyan("2.")} Run ${chalk.yellow("task-master list --with-subtasks")} to verify changes`,
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: "cyan",
|
||||
borderStyle: "round",
|
||||
margin: { top: 1 },
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!isSilentMode()) {
|
||||
console.log(
|
||||
boxen(chalk.yellow("No subtasks were cleared"), {
|
||||
padding: 1,
|
||||
borderColor: "yellow",
|
||||
borderStyle: "round",
|
||||
margin: { top: 1 },
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default clearSubtasks;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,17 @@
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import boxen from 'boxen';
|
||||
import path from "path";
|
||||
import chalk from "chalk";
|
||||
import boxen from "boxen";
|
||||
|
||||
import { log, readJSON, writeJSON, findTaskById } from '../utils.js';
|
||||
import { displayBanner } from '../ui.js';
|
||||
import { validateTaskDependencies } from '../dependency-manager.js';
|
||||
import { getDebugFlag } from '../config-manager.js';
|
||||
import updateSingleTaskStatus from './update-single-task-status.js';
|
||||
import generateTaskFiles from './generate-task-files.js';
|
||||
import { log, readJSON, writeJSON, findTaskById } from "../utils.js";
|
||||
import { displayBanner } from "../ui.js";
|
||||
import { validateTaskDependencies } from "../dependency-manager.js";
|
||||
import { getDebugFlag } from "../config-manager.js";
|
||||
import updateSingleTaskStatus from "./update-single-task-status.js";
|
||||
import generateTaskFiles from "./generate-task-files.js";
|
||||
import {
|
||||
isValidTaskStatus,
|
||||
TASK_STATUS_OPTIONS
|
||||
} from '../../../src/constants/task-status.js';
|
||||
isValidTaskStatus,
|
||||
TASK_STATUS_OPTIONS,
|
||||
} from "../../../src/constants/task-status.js";
|
||||
|
||||
/**
|
||||
* Set the status of a task
|
||||
@@ -22,102 +22,100 @@ import {
|
||||
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
||||
*/
|
||||
async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
||||
try {
|
||||
if (!isValidTaskStatus(newStatus)) {
|
||||
throw new Error(
|
||||
`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(', ')}`
|
||||
);
|
||||
}
|
||||
// Determine if we're in MCP mode by checking for mcpLog
|
||||
const isMcpMode = !!options?.mcpLog;
|
||||
try {
|
||||
if (!isValidTaskStatus(newStatus)) {
|
||||
throw new Error(
|
||||
`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(", ")}`
|
||||
);
|
||||
}
|
||||
// Determine if we're in MCP mode by checking for mcpLog
|
||||
const isMcpMode = !!options?.mcpLog;
|
||||
|
||||
// Only display UI elements if not in MCP mode
|
||||
if (!isMcpMode) {
|
||||
displayBanner();
|
||||
// Only display UI elements if not in MCP mode
|
||||
if (!isMcpMode) {
|
||||
console.log(
|
||||
boxen(chalk.white.bold(`Updating Task Status to: ${newStatus}`), {
|
||||
padding: 1,
|
||||
borderColor: "blue",
|
||||
borderStyle: "round",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
boxen(chalk.white.bold(`Updating Task Status to: ${newStatus}`), {
|
||||
padding: 1,
|
||||
borderColor: 'blue',
|
||||
borderStyle: 'round'
|
||||
})
|
||||
);
|
||||
}
|
||||
log("info", `Reading tasks from ${tasksPath}...`);
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||
}
|
||||
|
||||
log('info', `Reading tasks from ${tasksPath}...`);
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||
}
|
||||
// Handle multiple task IDs (comma-separated)
|
||||
const taskIds = taskIdInput.split(",").map((id) => id.trim());
|
||||
const updatedTasks = [];
|
||||
|
||||
// Handle multiple task IDs (comma-separated)
|
||||
const taskIds = taskIdInput.split(',').map((id) => id.trim());
|
||||
const updatedTasks = [];
|
||||
// Update each task
|
||||
for (const id of taskIds) {
|
||||
await updateSingleTaskStatus(tasksPath, id, newStatus, data, !isMcpMode);
|
||||
updatedTasks.push(id);
|
||||
}
|
||||
|
||||
// Update each task
|
||||
for (const id of taskIds) {
|
||||
await updateSingleTaskStatus(tasksPath, id, newStatus, data, !isMcpMode);
|
||||
updatedTasks.push(id);
|
||||
}
|
||||
// Write the updated tasks to the file
|
||||
writeJSON(tasksPath, data);
|
||||
|
||||
// Write the updated tasks to the file
|
||||
writeJSON(tasksPath, data);
|
||||
// Validate dependencies after status update
|
||||
log("info", "Validating dependencies after status update...");
|
||||
validateTaskDependencies(data.tasks);
|
||||
|
||||
// Validate dependencies after status update
|
||||
log('info', 'Validating dependencies after status update...');
|
||||
validateTaskDependencies(data.tasks);
|
||||
// Generate individual task files
|
||||
log("info", "Regenerating task files...");
|
||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
||||
mcpLog: options.mcpLog,
|
||||
});
|
||||
|
||||
// Generate individual task files
|
||||
log('info', 'Regenerating task files...');
|
||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
||||
mcpLog: options.mcpLog
|
||||
});
|
||||
// Display success message - only in CLI mode
|
||||
if (!isMcpMode) {
|
||||
for (const id of updatedTasks) {
|
||||
const task = findTaskById(data.tasks, id);
|
||||
const taskName = task ? task.title : id;
|
||||
|
||||
// Display success message - only in CLI mode
|
||||
if (!isMcpMode) {
|
||||
for (const id of updatedTasks) {
|
||||
const task = findTaskById(data.tasks, id);
|
||||
const taskName = task ? task.title : id;
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold(`Successfully updated task ${id} status:`) +
|
||||
"\n" +
|
||||
`From: ${chalk.yellow(task ? task.status : "unknown")}\n` +
|
||||
`To: ${chalk.green(newStatus)}`,
|
||||
{ padding: 1, borderColor: "green", borderStyle: "round" }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold(`Successfully updated task ${id} status:`) +
|
||||
'\n' +
|
||||
`From: ${chalk.yellow(task ? task.status : 'unknown')}\n` +
|
||||
`To: ${chalk.green(newStatus)}`,
|
||||
{ padding: 1, borderColor: 'green', borderStyle: 'round' }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
// Return success value for programmatic use
|
||||
return {
|
||||
success: true,
|
||||
updatedTasks: updatedTasks.map((id) => ({
|
||||
id,
|
||||
status: newStatus,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
log("error", `Error setting task status: ${error.message}`);
|
||||
|
||||
// Return success value for programmatic use
|
||||
return {
|
||||
success: true,
|
||||
updatedTasks: updatedTasks.map((id) => ({
|
||||
id,
|
||||
status: newStatus
|
||||
}))
|
||||
};
|
||||
} catch (error) {
|
||||
log('error', `Error setting task status: ${error.message}`);
|
||||
// Only show error UI in CLI mode
|
||||
if (!options?.mcpLog) {
|
||||
console.error(chalk.red(`Error: ${error.message}`));
|
||||
|
||||
// Only show error UI in CLI mode
|
||||
if (!options?.mcpLog) {
|
||||
console.error(chalk.red(`Error: ${error.message}`));
|
||||
// Pass session to getDebugFlag
|
||||
if (getDebugFlag(options?.session)) {
|
||||
// Use getter
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
// Pass session to getDebugFlag
|
||||
if (getDebugFlag(options?.session)) {
|
||||
// Use getter
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
} else {
|
||||
// In MCP mode, throw the error for the caller to handle
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
process.exit(1);
|
||||
} else {
|
||||
// In MCP mode, throw the error for the caller to handle
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default setTaskStatus;
|
||||
|
||||
@@ -40,7 +40,7 @@ const warmGradient = gradient(['#fb8b24', '#e36414', '#9a031e']);
|
||||
function displayBanner() {
|
||||
if (isSilentMode()) return;
|
||||
|
||||
console.clear();
|
||||
// console.clear(); // Removing this to avoid clearing the terminal per command
|
||||
const bannerText = figlet.textSync('Task Master', {
|
||||
font: 'Standard',
|
||||
horizontalLayout: 'default',
|
||||
@@ -78,6 +78,8 @@ function displayBanner() {
|
||||
* @returns {Object} Spinner object
|
||||
*/
|
||||
function startLoadingIndicator(message) {
|
||||
if (isSilentMode()) return null;
|
||||
|
||||
const spinner = ora({
|
||||
text: message,
|
||||
color: 'cyan'
|
||||
@@ -87,15 +89,75 @@ function startLoadingIndicator(message) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a loading indicator
|
||||
* Stop a loading indicator (basic stop, no success/fail indicator)
|
||||
* @param {Object} spinner - Spinner object to stop
|
||||
*/
|
||||
function stopLoadingIndicator(spinner) {
|
||||
if (spinner && spinner.stop) {
|
||||
if (spinner && typeof spinner.stop === 'function') {
|
||||
spinner.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a loading indicator with success (shows checkmark)
|
||||
* @param {Object} spinner - Spinner object to complete
|
||||
* @param {string} message - Optional success message (defaults to current text)
|
||||
*/
|
||||
function succeedLoadingIndicator(spinner, message = null) {
|
||||
if (spinner && typeof spinner.succeed === 'function') {
|
||||
if (message) {
|
||||
spinner.succeed(message);
|
||||
} else {
|
||||
spinner.succeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a loading indicator with failure (shows X)
|
||||
* @param {Object} spinner - Spinner object to fail
|
||||
* @param {string} message - Optional failure message (defaults to current text)
|
||||
*/
|
||||
function failLoadingIndicator(spinner, message = null) {
|
||||
if (spinner && typeof spinner.fail === 'function') {
|
||||
if (message) {
|
||||
spinner.fail(message);
|
||||
} else {
|
||||
spinner.fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a loading indicator with warning (shows warning symbol)
|
||||
* @param {Object} spinner - Spinner object to warn
|
||||
* @param {string} message - Optional warning message (defaults to current text)
|
||||
*/
|
||||
function warnLoadingIndicator(spinner, message = null) {
|
||||
if (spinner && typeof spinner.warn === 'function') {
|
||||
if (message) {
|
||||
spinner.warn(message);
|
||||
} else {
|
||||
spinner.warn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a loading indicator with info (shows info symbol)
|
||||
* @param {Object} spinner - Spinner object to complete with info
|
||||
* @param {string} message - Optional info message (defaults to current text)
|
||||
*/
|
||||
function infoLoadingIndicator(spinner, message = null) {
|
||||
if (spinner && typeof spinner.info === 'function') {
|
||||
if (message) {
|
||||
spinner.info(message);
|
||||
} else {
|
||||
spinner.info();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a colored progress bar
|
||||
* @param {number} percent - The completion percentage
|
||||
@@ -232,14 +294,14 @@ function getStatusWithColor(status, forTable = false) {
|
||||
}
|
||||
|
||||
const statusConfig = {
|
||||
done: { color: chalk.green, icon: '✅', tableIcon: '✓' },
|
||||
completed: { color: chalk.green, icon: '✅', tableIcon: '✓' },
|
||||
pending: { color: chalk.yellow, icon: '⏱️', tableIcon: '⏱' },
|
||||
done: { color: chalk.green, icon: '✓', tableIcon: '✓' },
|
||||
completed: { color: chalk.green, icon: '✓', tableIcon: '✓' },
|
||||
pending: { color: chalk.yellow, icon: '○', tableIcon: '⏱' },
|
||||
'in-progress': { color: chalk.hex('#FFA500'), icon: '🔄', tableIcon: '►' },
|
||||
deferred: { color: chalk.gray, icon: '⏱️', tableIcon: '⏱' },
|
||||
blocked: { color: chalk.red, icon: '❌', tableIcon: '✗' },
|
||||
review: { color: chalk.magenta, icon: '👀', tableIcon: '👁' },
|
||||
cancelled: { color: chalk.gray, icon: '❌', tableIcon: '✗' }
|
||||
deferred: { color: chalk.gray, icon: 'x', tableIcon: '⏱' },
|
||||
blocked: { color: chalk.red, icon: '!', tableIcon: '✗' },
|
||||
review: { color: chalk.magenta, icon: '?', tableIcon: '?' },
|
||||
cancelled: { color: chalk.gray, icon: '❌', tableIcon: 'x' }
|
||||
};
|
||||
|
||||
const config = statusConfig[status.toLowerCase()] || {
|
||||
@@ -383,8 +445,6 @@ function formatDependenciesWithStatus(
|
||||
* Display a comprehensive help guide
|
||||
*/
|
||||
function displayHelp() {
|
||||
displayBanner();
|
||||
|
||||
// Get terminal width - moved to top of function to make it available throughout
|
||||
const terminalWidth = process.stdout.columns || 100; // Default to 100 if can't detect
|
||||
|
||||
@@ -772,8 +832,6 @@ function truncateString(str, maxLength) {
|
||||
* @param {string} tasksPath - Path to the tasks.json file
|
||||
*/
|
||||
async function displayNextTask(tasksPath, complexityReportPath = null) {
|
||||
displayBanner();
|
||||
|
||||
// Read the tasks file
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
@@ -1044,8 +1102,6 @@ async function displayTaskById(
|
||||
complexityReportPath = null,
|
||||
statusFilter = null
|
||||
) {
|
||||
displayBanner();
|
||||
|
||||
// Read the tasks file
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
@@ -1500,8 +1556,6 @@ async function displayTaskById(
|
||||
* @param {string} reportPath - Path to the complexity report file
|
||||
*/
|
||||
async function displayComplexityReport(reportPath) {
|
||||
displayBanner();
|
||||
|
||||
// Check if the report exists
|
||||
if (!fs.existsSync(reportPath)) {
|
||||
console.log(
|
||||
@@ -2472,5 +2526,8 @@ export {
|
||||
displayModelConfiguration,
|
||||
displayAvailableModels,
|
||||
displayAiUsageSummary,
|
||||
displayMultipleTasksSummary
|
||||
succeedLoadingIndicator,
|
||||
failLoadingIndicator,
|
||||
warnLoadingIndicator,
|
||||
infoLoadingIndicator
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user