v1.4.0: Enhanced context for Perplexity AI, fixed command parameter inconsistencies, added missing parameters to update command, improved documentation
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-task-master",
|
"name": "claude-task-master",
|
||||||
"version": "1.3.2",
|
"version": "1.4.0",
|
||||||
"description": "A task management system for AI-driven development with Claude",
|
"description": "A task management system for AI-driven development with Claude",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -77,6 +77,26 @@ node scripts/dev.js list --with-subtasks
|
|||||||
node scripts/dev.js list --status=pending --with-subtasks
|
node scripts/dev.js list --status=pending --with-subtasks
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Updating Tasks
|
||||||
|
|
||||||
|
The `update` command allows you to update tasks based on new information or implementation changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update tasks starting from ID 4 with a new prompt
|
||||||
|
node scripts/dev.js update --from=4 --prompt="Refactor tasks from ID 4 onward to use Express instead of Fastify"
|
||||||
|
|
||||||
|
# Update all tasks (default from=1)
|
||||||
|
node scripts/dev.js update --prompt="Add authentication to all relevant tasks"
|
||||||
|
|
||||||
|
# Specify a different tasks file
|
||||||
|
node scripts/dev.js update --file=custom-tasks.json --from=5 --prompt="Change database from MongoDB to PostgreSQL"
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- The `--prompt` parameter is required and should explain the changes or new context
|
||||||
|
- Only tasks that aren't marked as 'done' will be updated
|
||||||
|
- Tasks with ID >= the specified --from value will be updated
|
||||||
|
|
||||||
## Expanding Tasks
|
## Expanding Tasks
|
||||||
|
|
||||||
The `expand` command allows you to break down tasks into subtasks for more detailed implementation:
|
The `expand` command allows you to break down tasks into subtasks for more detailed implementation:
|
||||||
@@ -86,7 +106,7 @@ The `expand` command allows you to break down tasks into subtasks for more detai
|
|||||||
node scripts/dev.js expand --id=3
|
node scripts/dev.js expand --id=3
|
||||||
|
|
||||||
# Expand a specific task with 5 subtasks
|
# Expand a specific task with 5 subtasks
|
||||||
node scripts/dev.js expand --id=3 --subtasks=5
|
node scripts/dev.js expand --id=3 --num=5
|
||||||
|
|
||||||
# Expand a task with additional context
|
# Expand a task with additional context
|
||||||
node scripts/dev.js expand --id=3 --prompt="Focus on security aspects"
|
node scripts/dev.js expand --id=3 --prompt="Focus on security aspects"
|
||||||
|
|||||||
149
scripts/dev.js
149
scripts/dev.js
@@ -9,7 +9,9 @@
|
|||||||
* -> Optional --tasks parameter limits the number of tasks generated.
|
* -> Optional --tasks parameter limits the number of tasks generated.
|
||||||
*
|
*
|
||||||
* 2) update --from=5 --prompt="We changed from Slack to Discord."
|
* 2) update --from=5 --prompt="We changed from Slack to Discord."
|
||||||
* -> Regenerates tasks from ID >= 5 using the provided prompt (or naive approach).
|
* -> Regenerates tasks from ID >= 5 using the provided prompt.
|
||||||
|
* -> Only updates tasks that aren't marked as 'done'.
|
||||||
|
* -> The --prompt parameter is required and should explain the changes or new context.
|
||||||
*
|
*
|
||||||
* 3) generate
|
* 3) generate
|
||||||
* -> Generates per-task files (e.g., task_001.txt) from tasks.json
|
* -> Generates per-task files (e.g., task_001.txt) from tasks.json
|
||||||
@@ -21,10 +23,12 @@
|
|||||||
* 5) list
|
* 5) list
|
||||||
* -> Lists tasks in a brief console view (ID, title, status).
|
* -> Lists tasks in a brief console view (ID, title, status).
|
||||||
*
|
*
|
||||||
* 6) expand --id=3 --subtasks=5 [--prompt="Additional context"]
|
* 6) expand --id=3 [--num=5] [--no-research] [--prompt="Additional context"]
|
||||||
* -> Expands a task with subtasks for more detailed implementation.
|
* -> Expands a task with subtasks for more detailed implementation.
|
||||||
* -> Use --all instead of --id to expand all tasks.
|
* -> Use --all instead of --id to expand all tasks.
|
||||||
* -> Optional --subtasks parameter controls number of subtasks (default: 3).
|
* -> Optional --num parameter controls number of subtasks (default: 3).
|
||||||
|
* -> Uses Perplexity AI for research-backed subtask generation by default.
|
||||||
|
* -> Use --no-research to disable research-backed generation.
|
||||||
* -> Add --force when using --all to regenerate subtasks for tasks that already have them.
|
* -> Add --force when using --all to regenerate subtasks for tasks that already have them.
|
||||||
* -> Note: Tasks marked as 'done' or 'completed' are always skipped.
|
* -> Note: Tasks marked as 'done' or 'completed' are always skipped.
|
||||||
*
|
*
|
||||||
@@ -35,7 +39,8 @@
|
|||||||
* node dev.js generate
|
* node dev.js generate
|
||||||
* node dev.js set-status --id=3 --status=done
|
* node dev.js set-status --id=3 --status=done
|
||||||
* node dev.js list
|
* node dev.js list
|
||||||
* node dev.js expand --id=3 --subtasks=5
|
* node dev.js expand --id=3 --num=5
|
||||||
|
* node dev.js expand --id=3 --no-research
|
||||||
* node dev.js expand --all
|
* node dev.js expand --all
|
||||||
* node dev.js expand --all --force
|
* node dev.js expand --all --force
|
||||||
*/
|
*/
|
||||||
@@ -669,7 +674,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
* @param {boolean} useResearch - Whether to use Perplexity for research-backed subtask generation
|
* @param {boolean} useResearch - Whether to use Perplexity for research-backed subtask generation
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function expandTask(taskId, numSubtasks = CONFIG.defaultSubtasks, useResearch = false) {
|
async function expandTask(taskId, numSubtasks = CONFIG.defaultSubtasks, useResearch = false, additionalContext = '') {
|
||||||
try {
|
try {
|
||||||
// Get the tasks
|
// Get the tasks
|
||||||
const tasksData = readJSON(path.join(process.cwd(), 'tasks', 'tasks.json'));
|
const tasksData = readJSON(path.join(process.cwd(), 'tasks', 'tasks.json'));
|
||||||
@@ -700,9 +705,9 @@ async function expandTask(taskId, numSubtasks = CONFIG.defaultSubtasks, useResea
|
|||||||
let subtasks;
|
let subtasks;
|
||||||
if (useResearch) {
|
if (useResearch) {
|
||||||
console.log(chalk.blue(`Using Perplexity AI for research-backed subtask generation...`));
|
console.log(chalk.blue(`Using Perplexity AI for research-backed subtask generation...`));
|
||||||
subtasks = await generateSubtasksWithPerplexity(task, numSubtasks, nextSubtaskId);
|
subtasks = await generateSubtasksWithPerplexity(task, numSubtasks, nextSubtaskId, additionalContext);
|
||||||
} else {
|
} else {
|
||||||
subtasks = await generateSubtasks(task, numSubtasks, nextSubtaskId);
|
subtasks = await generateSubtasks(task, numSubtasks, nextSubtaskId, additionalContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the subtasks to the task
|
// Add the subtasks to the task
|
||||||
@@ -732,7 +737,7 @@ async function expandTask(taskId, numSubtasks = CONFIG.defaultSubtasks, useResea
|
|||||||
* @param {boolean} useResearch - Whether to use Perplexity for research-backed subtask generation
|
* @param {boolean} useResearch - Whether to use Perplexity for research-backed subtask generation
|
||||||
* @returns {Promise<number>} - The number of tasks expanded
|
* @returns {Promise<number>} - The number of tasks expanded
|
||||||
*/
|
*/
|
||||||
async function expandAllTasks(numSubtasks = CONFIG.defaultSubtasks, useResearch = false) {
|
async function expandAllTasks(numSubtasks = CONFIG.defaultSubtasks, useResearch = false, additionalContext = '', forceFlag = false) {
|
||||||
try {
|
try {
|
||||||
// Get the tasks
|
// Get the tasks
|
||||||
const tasksData = readJSON(path.join(process.cwd(), 'tasks', 'tasks.json'));
|
const tasksData = readJSON(path.join(process.cwd(), 'tasks', 'tasks.json'));
|
||||||
@@ -759,7 +764,7 @@ async function expandAllTasks(numSubtasks = CONFIG.defaultSubtasks, useResearch
|
|||||||
// Expand each task
|
// Expand each task
|
||||||
for (const task of tasksToExpand) {
|
for (const task of tasksToExpand) {
|
||||||
console.log(chalk.blue(`\nExpanding task ${task.id}: ${task.title}`));
|
console.log(chalk.blue(`\nExpanding task ${task.id}: ${task.title}`));
|
||||||
await expandTask(task.id, numSubtasks, useResearch);
|
await expandTask(task.id, numSubtasks, useResearch, additionalContext);
|
||||||
tasksExpanded++;
|
tasksExpanded++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1007,7 +1012,7 @@ function parseSubtasksFromText(text, startId, expectedCount) {
|
|||||||
* @param {number} nextSubtaskId - The ID to start assigning to subtasks
|
* @param {number} nextSubtaskId - The ID to start assigning to subtasks
|
||||||
* @returns {Promise<Array>} - The generated subtasks
|
* @returns {Promise<Array>} - The generated subtasks
|
||||||
*/
|
*/
|
||||||
async function generateSubtasksWithPerplexity(task, numSubtasks = 3, nextSubtaskId = 1) {
|
async function generateSubtasksWithPerplexity(task, numSubtasks = 3, nextSubtaskId = 1, additionalContext = '') {
|
||||||
const { title, description, details = '', subtasks = [] } = task;
|
const { title, description, details = '', subtasks = [] } = task;
|
||||||
|
|
||||||
console.log(chalk.blue(`Generating ${numSubtasks} subtasks for task: ${title}`));
|
console.log(chalk.blue(`Generating ${numSubtasks} subtasks for task: ${title}`));
|
||||||
@@ -1028,28 +1033,100 @@ async function generateSubtasksWithPerplexity(task, numSubtasks = 3, nextSubtask
|
|||||||
if (tasksData.meta && tasksData.meta.source) {
|
if (tasksData.meta && tasksData.meta.source) {
|
||||||
try {
|
try {
|
||||||
prdContent = fs.readFileSync(path.join(process.cwd(), tasksData.meta.source), 'utf8');
|
prdContent = fs.readFileSync(path.join(process.cwd(), tasksData.meta.source), 'utf8');
|
||||||
|
console.log(chalk.green(`Successfully loaded PRD from ${tasksData.meta.source} (${prdContent.length} characters)`));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(chalk.yellow(`Could not read PRD at ${tasksData.meta.source}. Proceeding without it.`));
|
console.log(chalk.yellow(`Could not read PRD at ${tasksData.meta.source}. Proceeding without it.`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the prompt for Perplexity/Anthropic
|
// Get the specific task file for more detailed context if available
|
||||||
const prompt = `I need to break down the following task into ${numSubtasks} detailed subtasks:
|
let taskFileContent = '';
|
||||||
|
try {
|
||||||
|
const taskFileName = `task_${String(task.id).padStart(3, '0')}.txt`;
|
||||||
|
const taskFilePath = path.join(process.cwd(), 'tasks', taskFileName);
|
||||||
|
if (fs.existsSync(taskFilePath)) {
|
||||||
|
taskFileContent = fs.readFileSync(taskFilePath, 'utf8');
|
||||||
|
console.log(chalk.green(`Successfully loaded task file ${taskFileName} for additional context`));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(chalk.yellow(`Could not read task file for task ${task.id}. Proceeding without it.`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get dependency task details for better context
|
||||||
|
let dependencyDetails = '';
|
||||||
|
if (task.dependencies && task.dependencies.length > 0) {
|
||||||
|
dependencyDetails = 'Dependency Tasks:\n';
|
||||||
|
for (const depId of task.dependencies) {
|
||||||
|
const depTask = tasksData.tasks.find(t => t.id === depId);
|
||||||
|
if (depTask) {
|
||||||
|
dependencyDetails += `Task ${depId}: ${depTask.title}\n`;
|
||||||
|
dependencyDetails += `Description: ${depTask.description}\n`;
|
||||||
|
if (depTask.details) {
|
||||||
|
dependencyDetails += `Details: ${depTask.details.substring(0, 200)}${depTask.details.length > 200 ? '...' : ''}\n`;
|
||||||
|
}
|
||||||
|
dependencyDetails += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract project metadata for context
|
||||||
|
const projectContext = tasksData.meta ?
|
||||||
|
`Project: ${tasksData.meta.projectName || 'Unknown'}
|
||||||
|
Version: ${tasksData.meta.version || '1.0.0'}
|
||||||
|
Description: ${tasksData.meta.description || 'No description available'}` : '';
|
||||||
|
|
||||||
|
// Construct the prompt for Perplexity/Anthropic with enhanced context
|
||||||
|
const prompt = `I need to break down the following task into ${numSubtasks} detailed subtasks for a software development project.
|
||||||
|
|
||||||
|
${projectContext}
|
||||||
|
|
||||||
|
CURRENT TASK:
|
||||||
|
Task ID: ${task.id}
|
||||||
Task Title: ${title}
|
Task Title: ${title}
|
||||||
Task Description: ${description}
|
Task Description: ${description}
|
||||||
|
Priority: ${task.priority || 'medium'}
|
||||||
Additional Details: ${details}
|
Additional Details: ${details}
|
||||||
|
${additionalContext ? `\nADDITIONAL CONTEXT PROVIDED BY USER:\n${additionalContext}` : ''}
|
||||||
|
|
||||||
|
${taskFileContent ? `DETAILED TASK INFORMATION:
|
||||||
|
${taskFileContent}` : ''}
|
||||||
|
|
||||||
|
${dependencyDetails ? dependencyDetails : ''}
|
||||||
|
|
||||||
${subtasks.length > 0 ? `Existing Subtasks:
|
${subtasks.length > 0 ? `Existing Subtasks:
|
||||||
${subtasks.map(st => `- ${st.title}: ${st.description}`).join('\n')}` : ''}
|
${subtasks.map(st => `- ${st.title}: ${st.description}`).join('\n')}` : ''}
|
||||||
|
|
||||||
${prdContent ? `Here is the Product Requirements Document for context:
|
${prdContent ? `PRODUCT REQUIREMENTS DOCUMENT:
|
||||||
${prdContent}` : ''}
|
${prdContent}` : ''}
|
||||||
|
|
||||||
${tasksData.tasks ? `Here are the other tasks in the project for context:
|
${tasksData.tasks ? `PROJECT CONTEXT - OTHER RELATED TASKS:
|
||||||
${JSON.stringify(tasksData.tasks.filter(t => t.id !== task.id).map(t => ({ id: t.id, title: t.title, description: t.description })), null, 2)}` : ''}
|
${JSON.stringify(
|
||||||
|
tasksData.tasks
|
||||||
|
.filter(t => t.id !== task.id)
|
||||||
|
// Prioritize tasks that are dependencies or depend on this task
|
||||||
|
.sort((a, b) => {
|
||||||
|
const aIsRelated = task.dependencies?.includes(a.id) || a.dependencies?.includes(task.id);
|
||||||
|
const bIsRelated = task.dependencies?.includes(b.id) || b.dependencies?.includes(task.id);
|
||||||
|
return bIsRelated - aIsRelated;
|
||||||
|
})
|
||||||
|
.slice(0, 5) // Limit to 5 most relevant tasks to avoid context overload
|
||||||
|
.map(t => ({
|
||||||
|
id: t.id,
|
||||||
|
title: t.title,
|
||||||
|
description: t.description,
|
||||||
|
status: t.status,
|
||||||
|
dependencies: t.dependencies
|
||||||
|
})),
|
||||||
|
null, 2
|
||||||
|
)}` : ''}
|
||||||
|
|
||||||
Please generate ${numSubtasks} subtasks. For each subtask, provide:
|
Please generate ${numSubtasks} subtasks that are:
|
||||||
|
1. Specific and actionable
|
||||||
|
2. Relevant to the current technology stack and project requirements
|
||||||
|
3. Properly sequenced with clear dependencies
|
||||||
|
4. Detailed enough to be implemented without further clarification
|
||||||
|
|
||||||
|
For each subtask, provide:
|
||||||
1. A clear, concise title
|
1. A clear, concise title
|
||||||
2. A detailed description explaining what needs to be done
|
2. A detailed description explaining what needs to be done
|
||||||
3. Dependencies (if any) - list the IDs of tasks this subtask depends on
|
3. Dependencies (if any) - list the IDs of tasks this subtask depends on
|
||||||
@@ -1065,7 +1142,7 @@ Acceptance Criteria: [List of criteria]
|
|||||||
Subtask 2: [Title]
|
Subtask 2: [Title]
|
||||||
...
|
...
|
||||||
|
|
||||||
Research the task thoroughly and ensure the subtasks are comprehensive, specific, and actionable.`;
|
Research the task thoroughly and ensure the subtasks are comprehensive, specific, and actionable. Focus on technical implementation details rather than generic steps.`;
|
||||||
|
|
||||||
// Start loading indicator
|
// Start loading indicator
|
||||||
const loadingInterval = startLoadingIndicator('Researching and generating subtasks with AI');
|
const loadingInterval = startLoadingIndicator('Researching and generating subtasks with AI');
|
||||||
@@ -1098,7 +1175,7 @@ Research the task thoroughly and ensure the subtasks are comprehensive, specific
|
|||||||
model: MODEL,
|
model: MODEL,
|
||||||
max_tokens: MAX_TOKENS,
|
max_tokens: MAX_TOKENS,
|
||||||
temperature: TEMPERATURE,
|
temperature: TEMPERATURE,
|
||||||
system: "You are an expert software developer and project manager. Your task is to break down software development tasks into detailed subtasks.",
|
system: "You are an expert software developer and project manager. Your task is to break down software development tasks into detailed subtasks that are specific, actionable, and technically relevant.",
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
@@ -1164,14 +1241,24 @@ async function main() {
|
|||||||
|
|
||||||
program
|
program
|
||||||
.command('update')
|
.command('update')
|
||||||
.description('Update tasks based on the PRD')
|
.description('Update tasks based on new information or implementation changes')
|
||||||
.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('--from <id>', 'Task ID to start updating from (tasks with ID >= this value will be updated)', '1')
|
||||||
|
.option('-p, --prompt <text>', 'Prompt explaining the changes or new context (required)')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const tasksPath = options.file;
|
const tasksPath = options.file;
|
||||||
|
const fromId = parseInt(options.from, 10);
|
||||||
|
const prompt = options.prompt;
|
||||||
|
|
||||||
console.log(chalk.blue(`Updating tasks from: ${tasksPath}`));
|
if (!prompt) {
|
||||||
|
console.error(chalk.red('Error: --prompt parameter is required. Please provide information about the changes.'));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
await updateTasks(tasksPath);
|
console.log(chalk.blue(`Updating tasks from ID >= ${fromId} with prompt: "${prompt}"`));
|
||||||
|
console.log(chalk.blue(`Tasks file: ${tasksPath}`));
|
||||||
|
|
||||||
|
await updateTasks(tasksPath, fromId, prompt);
|
||||||
});
|
});
|
||||||
|
|
||||||
program
|
program
|
||||||
@@ -1233,7 +1320,8 @@ async function main() {
|
|||||||
.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', CONFIG.defaultSubtasks.toString())
|
.option('-n, --num <number>', 'Number of subtasks to generate', CONFIG.defaultSubtasks.toString())
|
||||||
.option('-r, --research', 'Use Perplexity AI for research-backed subtask generation')
|
.option('-r, --no-research', 'Disable Perplexity AI for research-backed 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(async (options) => {
|
.action(async (options) => {
|
||||||
const tasksPath = options.file;
|
const tasksPath = options.file;
|
||||||
@@ -1241,20 +1329,31 @@ async function main() {
|
|||||||
const allFlag = options.all;
|
const allFlag = options.all;
|
||||||
const numSubtasks = parseInt(options.num, 10);
|
const numSubtasks = parseInt(options.num, 10);
|
||||||
const forceFlag = options.force;
|
const forceFlag = options.force;
|
||||||
const useResearch = options.research;
|
const useResearch = options.research !== false; // Default to true unless explicitly disabled
|
||||||
|
const additionalContext = options.prompt || '';
|
||||||
|
|
||||||
if (allFlag) {
|
if (allFlag) {
|
||||||
console.log(chalk.blue(`Expanding all tasks with ${numSubtasks} subtasks each...`));
|
console.log(chalk.blue(`Expanding all tasks with ${numSubtasks} subtasks each...`));
|
||||||
if (useResearch) {
|
if (useResearch) {
|
||||||
console.log(chalk.blue('Using Perplexity AI for research-backed subtask generation'));
|
console.log(chalk.blue('Using Perplexity AI for research-backed subtask generation'));
|
||||||
|
} else {
|
||||||
|
console.log(chalk.yellow('Research-backed subtask generation disabled'));
|
||||||
}
|
}
|
||||||
await expandAllTasks(numSubtasks, useResearch);
|
if (additionalContext) {
|
||||||
|
console.log(chalk.blue(`Additional context: "${additionalContext}"`));
|
||||||
|
}
|
||||||
|
await expandAllTasks(numSubtasks, useResearch, additionalContext, forceFlag);
|
||||||
} else if (idArg) {
|
} else if (idArg) {
|
||||||
console.log(chalk.blue(`Expanding task ${idArg} with ${numSubtasks} subtasks...`));
|
console.log(chalk.blue(`Expanding task ${idArg} with ${numSubtasks} subtasks...`));
|
||||||
if (useResearch) {
|
if (useResearch) {
|
||||||
console.log(chalk.blue('Using Perplexity AI for research-backed subtask generation'));
|
console.log(chalk.blue('Using Perplexity AI for research-backed subtask generation'));
|
||||||
|
} else {
|
||||||
|
console.log(chalk.yellow('Research-backed subtask generation disabled'));
|
||||||
}
|
}
|
||||||
await expandTask(idArg, numSubtasks, useResearch);
|
if (additionalContext) {
|
||||||
|
console.log(chalk.blue(`Additional context: "${additionalContext}"`));
|
||||||
|
}
|
||||||
|
await expandTask(idArg, numSubtasks, useResearch, additionalContext);
|
||||||
} else {
|
} else {
|
||||||
console.error(chalk.red('Error: Please specify a task ID with --id=<id> or use --all to expand all tasks.'));
|
console.error(chalk.red('Error: Please specify a task ID with --id=<id> or use --all to expand all tasks.'));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user