refactor(init): Fix init command execution and argument handling

Centralizes init command logic within the main CLI structure. The action handler in commands.js now directly calls initializeProject from the init.js module, resolving issues with argument parsing (like -y) and removing the need for the separate bin/task-master-init.js executable. Updates package.json and bin/task-master.js accordingly.
This commit is contained in:
Eyal Toledano
2025-04-10 22:32:08 -04:00
parent 6403e96ef9
commit a86e9affc5
7 changed files with 257 additions and 349 deletions

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env node
/**
* Claude Task Master Init
* Direct executable for the init command
*/
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Get the path to the init script
const initScriptPath = resolve(__dirname, '../scripts/init.js');
// Pass through all arguments
const args = process.argv.slice(2);
// Spawn the init script with all arguments
const child = spawn('node', [initScriptPath, ...args], {
stdio: 'inherit',
cwd: process.cwd()
});
// Handle exit
child.on('close', (code) => {
process.exit(code);
});

View File

@@ -225,47 +225,47 @@ function createDevScriptAction(commandName) {
};
}
// Special case for the 'init' command which uses a different script
function registerInitCommand(program) {
program
.command('init')
.description('Initialize a new project')
.option('-y, --yes', 'Skip prompts and use default values')
.option('-n, --name <name>', 'Project name')
.option('-d, --description <description>', 'Project description')
.option('-v, --version <version>', 'Project version')
.option('-a, --author <author>', 'Author name')
.option('--skip-install', 'Skip installing dependencies')
.option('--dry-run', 'Show what would be done without making changes')
.action((options) => {
// Pass through any options to the init script
const args = [
'--yes',
'name',
'description',
'version',
'author',
'skip-install',
'dry-run'
]
.filter((opt) => options[opt])
.map((opt) => {
if (opt === 'yes' || opt === 'skip-install' || opt === 'dry-run') {
return `--${opt}`;
}
return `--${opt}=${options[opt]}`;
});
// // Special case for the 'init' command which uses a different script
// function registerInitCommand(program) {
// program
// .command('init')
// .description('Initialize a new project')
// .option('-y, --yes', 'Skip prompts and use default values')
// .option('-n, --name <name>', 'Project name')
// .option('-d, --description <description>', 'Project description')
// .option('-v, --version <version>', 'Project version')
// .option('-a, --author <author>', 'Author name')
// .option('--skip-install', 'Skip installing dependencies')
// .option('--dry-run', 'Show what would be done without making changes')
// .action((options) => {
// // Pass through any options to the init script
// const args = [
// '--yes',
// 'name',
// 'description',
// 'version',
// 'author',
// 'skip-install',
// 'dry-run'
// ]
// .filter((opt) => options[opt])
// .map((opt) => {
// if (opt === 'yes' || opt === 'skip-install' || opt === 'dry-run') {
// return `--${opt}`;
// }
// return `--${opt}=${options[opt]}`;
// });
const child = spawn('node', [initScriptPath, ...args], {
stdio: 'inherit',
cwd: process.cwd()
});
// const child = spawn('node', [initScriptPath, ...args], {
// stdio: 'inherit',
// cwd: process.cwd()
// });
child.on('close', (code) => {
process.exit(code);
});
});
}
// child.on('close', (code) => {
// process.exit(code);
// });
// });
// }
// Set up the command-line interface
const program = new Command();
@@ -286,8 +286,8 @@ program.on('--help', () => {
displayHelp();
});
// Add special case commands
registerInitCommand(program);
// // Add special case commands
// registerInitCommand(program);
program
.command('dev')
@@ -303,7 +303,7 @@ registerCommands(tempProgram);
// For each command in the temp instance, add a modified version to our actual program
tempProgram.commands.forEach((cmd) => {
if (['init', 'dev'].includes(cmd.name())) {
if (['dev'].includes(cmd.name())) {
// Skip commands we've already defined specially
return;
}

View File

@@ -1,56 +1,97 @@
import { z } from 'zod';
import { execSync } from 'child_process';
import { createContentResponse, createErrorResponse } from './utils.js'; // Only need response creators
import {
createContentResponse,
createErrorResponse,
getProjectRootFromSession
} from './utils.js';
export function registerInitializeProjectTool(server) {
server.addTool({
name: 'initialize_project', // snake_case for tool name
name: 'initialize_project',
description:
"Initializes a new Task Master project structure in the current working directory by running 'task-master init'.",
"Initializes a new Task Master project structure in the specified project directory by running 'task-master init'. If the project information required for the initialization is not available or provided by the user, prompt if the user wishes to provide them (name, description, author) or skip them. If the user wishes to skip, set the 'yes' flag to true and do not set any other parameters. DO NOT run the initialize_project tool without parameters.",
parameters: z.object({
projectName: z
.string()
.optional()
.describe('The name for the new project.'),
.describe(
'The name for the new project. If not provided, prompt the user for it.'
),
projectDescription: z
.string()
.optional()
.describe('A brief description for the project.'),
.describe(
'A brief description for the project. If not provided, prompt the user for it.'
),
projectVersion: z
.string()
.optional()
.describe("The initial version for the project (e.g., '0.1.0')."),
authorName: z.string().optional().describe("The author's name."),
.describe(
"The initial version for the project (e.g., '0.1.0'). User input not needed unless user requests to override."
),
authorName: z
.string()
.optional()
.describe(
"The author's name. User input not needed unless user requests to override."
),
skipInstall: z
.boolean()
.optional()
.default(false)
.describe('Skip installing dependencies automatically.'),
.describe(
'Skip installing dependencies automatically. Never do this unless you are sure the project is already installed.'
),
addAliases: z
.boolean()
.optional()
.default(false)
.describe('Add shell aliases (tm, taskmaster) to shell config file.'),
.describe(
'Add shell aliases (tm, taskmaster) to shell config file. User input not needed.'
),
yes: z
.boolean()
.optional()
.default(false)
.describe('Skip prompts and use default values or provided arguments.')
// projectRoot is not needed here as 'init' works on the current directory
.describe(
"Skip prompts and use default values or provided arguments. Use true if you wish to skip details like the project name, etc. If the project information required for the initialization is not available or provided by the user, prompt if the user wishes to provide them (name, description, author) or skip them. If the user wishes to skip, set the 'yes' flag to true and do not set any other parameters."
),
projectRoot: z
.string()
.optional()
.describe(
'Optional fallback project root if session data is unavailable. Setting a value is not needed unless you are running the tool from a different directory than the project root.'
)
}),
execute: async (args, { log }) => {
// Destructure context to get log
execute: async (args, { log, session }) => {
try {
log.info(
`Executing initialize_project with args: ${JSON.stringify(args)}`
);
// Construct the command arguments carefully
// Using npx ensures it uses the locally installed version if available, or fetches it
let command = 'npx task-master init';
let targetDirectory = getProjectRootFromSession(session, log);
if (!targetDirectory) {
if (args.projectRoot) {
targetDirectory = args.projectRoot;
log.warn(
`Using projectRoot argument as fallback: ${targetDirectory}`
);
} else {
log.error(
'Could not determine target directory for initialization from session or arguments.'
);
return createErrorResponse(
'Failed to determine target directory for initialization.'
);
}
}
log.info(`Target directory for initialization: ${targetDirectory}`);
let commandBase = 'npx task-master init';
const cliArgs = [];
if (args.projectName)
cliArgs.push(`--name "${args.projectName.replace(/"/g, '\\"')}"`); // Escape quotes
cliArgs.push(`--name "${args.projectName.replace(/"/g, '\\"')}"`);
if (args.projectDescription)
cliArgs.push(
`--description "${args.projectDescription.replace(/"/g, '\\"')}"`
@@ -63,36 +104,47 @@ export function registerInitializeProjectTool(server) {
cliArgs.push(`--author "${args.authorName.replace(/"/g, '\\"')}"`);
if (args.skipInstall) cliArgs.push('--skip-install');
if (args.addAliases) cliArgs.push('--aliases');
if (args.yes) cliArgs.push('--yes');
command += ' ' + cliArgs.join(' ');
log.debug(
`Value of args.yes before check: ${args.yes} (Type: ${typeof args.yes})`
);
if (args.yes === true) {
cliArgs.push('--yes');
log.info('Added --yes flag to cliArgs.');
} else {
log.info(`Did NOT add --yes flag. args.yes value: ${args.yes}`);
}
log.info(`Constructed command: ${command}`);
const command =
cliArgs.length > 0
? `${commandBase} ${cliArgs.join(' ')}`
: commandBase;
log.info(`FINAL Constructed command for execSync: ${command}`);
// Execute the command in the current working directory of the server process
// Capture stdout/stderr. Use a reasonable timeout (e.g., 5 minutes)
const output = execSync(command, {
encoding: 'utf8',
stdio: 'pipe',
timeout: 300000
timeout: 300000,
cwd: targetDirectory
});
log.info(`Initialization output:\n${output}`);
// Return a standard success response manually
return createContentResponse({
message: 'Taskmaster successfully initialized for this project.',
message: `Taskmaster successfully initialized in ${targetDirectory}.`,
next_step:
'Now that the project is initialized, the next step is to create the tasks by parsing a PRD. This will create the tasks folder and the initial task files. The parse-prd tool will required a prd.txt file as input in scripts/prd.txt. You can create a prd.txt file by asking the user about their idea, and then using the scripts/example_prd.txt file as a template to genrate a prd.txt file in scripts/. Before creating the PRD for the user, make sure you understand the idea fully and ask questions to eliminate ambiguity. You can then use the parse-prd tool to create the tasks. So: step 1 after initialization is to create a prd.txt file in scripts/prd.txt. Step 2 is to use the parse-prd tool to create the tasks. Do not bother looking for tasks after initialization, just use the parse-prd tool to create the tasks after creating a prd.txt from which to parse the tasks. '
'Now that the project is initialized, the next step is to create the tasks by parsing a PRD. This will create the tasks folder and the initial task files. The parse-prd tool will required a prd.txt file as input in scripts/prd.txt. You can create a prd.txt file by asking the user about their idea, and then using the scripts/example_prd.txt file as a template to genrate a prd.txt file in scripts/. Before creating the PRD for the user, make sure you understand the idea fully and ask questions to eliminate ambiguity. You can then use the parse-prd tool to create the tasks. So: step 1 after initialization is to create a prd.txt file in scripts/prd.txt. Step 2 is to use the parse-prd tool to create the tasks. Do not bother looking for tasks after initialization, just use the parse-prd tool to create the tasks after creating a prd.txt from which to parse the tasks. ',
output: output
});
} catch (error) {
// Catch errors from execSync or timeouts
const errorMessage = `Project initialization failed: ${error.message}`;
const errorMessage = `Project initialization failed: ${
error.message || 'Unknown error'
}`;
const errorDetails =
error.stderr?.toString() || error.stdout?.toString() || error.message; // Provide stderr/stdout if available
error.stderr?.toString() || error.stdout?.toString() || error.message;
log.error(`${errorMessage}\nDetails: ${errorDetails}`);
// Return a standard error response manually
return createErrorResponse(errorMessage, { details: errorDetails });
}
}

3
package-lock.json generated
View File

@@ -32,8 +32,7 @@
"bin": {
"task-master": "bin/task-master.js",
"task-master-init": "bin/task-master-init.js",
"task-master-mcp": "mcp-server/server.js",
"task-master-mcp-server": "mcp-server/server.js"
"task-master-mcp": "mcp-server/server.js"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",

View File

@@ -6,7 +6,6 @@
"type": "module",
"bin": {
"task-master": "bin/task-master.js",
"task-master-init": "bin/task-master-init.js",
"task-master-mcp": "mcp-server/server.js"
},
"scripts": {
@@ -16,7 +15,7 @@
"test:coverage": "node --experimental-vm-modules node_modules/.bin/jest --coverage",
"prepare-package": "node scripts/prepare-package.js",
"prepublishOnly": "npm run prepare-package",
"prepare": "chmod +x bin/task-master.js bin/task-master-init.js mcp-server/server.js",
"prepare": "chmod +x bin/task-master.js mcp-server/server.js",
"changeset": "changeset",
"release": "changeset publish",
"inspector": "npx @modelcontextprotocol/inspector node mcp-server/server.js",

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env node
/**
* Task Master
* Copyright (c) 2025 Eyal Toledano, Ralph Khreish
@@ -27,7 +25,6 @@ import chalk from 'chalk';
import figlet from 'figlet';
import boxen from 'boxen';
import gradient from 'gradient-string';
import { Command } from 'commander';
// Debug information
console.log('Node version:', process.version);
@@ -37,42 +34,6 @@ console.log('Script path:', import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Configure the CLI program
const program = new Command();
program
.name('task-master-init')
.description('Initialize a new Claude Task Master project')
.version('1.0.0') // Will be replaced by prepare-package script
.option('-y, --yes', 'Skip prompts and use default values')
.option('-n, --name <name>', 'Project name')
.option('-my_name <name>', 'Project name (alias for --name)')
.option('-d, --description <description>', 'Project description')
.option(
'-my_description <description>',
'Project description (alias for --description)'
)
.option('-v, --version <version>', 'Project version')
.option('-my_version <version>', 'Project version (alias for --version)')
.option('--my_name <name>', 'Project name (alias for --name)')
.option('-a, --author <author>', 'Author name')
.option('--skip-install', 'Skip installing dependencies')
.option('--dry-run', 'Show what would be done without making changes')
.option('--aliases', 'Add shell aliases (tm, taskmaster)')
.parse(process.argv);
const options = program.opts();
// Map custom aliases to standard options
if (options.my_name && !options.name) {
options.name = options.my_name;
}
if (options.my_description && !options.description) {
options.description = options.my_description;
}
if (options.my_version && !options.version) {
options.version = options.my_version;
}
// Define log levels
const LOG_LEVELS = {
debug: 0,
@@ -419,27 +380,35 @@ function copyTemplateFile(templateName, targetPath, replacements = {}) {
log('info', `Created file: ${targetPath}`);
}
// Main function to initialize a new project
async function initializeProject(options = {}) {
// Display the banner
// Main function to initialize a new project (Now relies solely on passed options)
async function initializeProject(options = {}) { // Receives options as argument
displayBanner();
// If options are provided, use them directly without prompting
if (options.projectName && options.projectDescription) {
const projectName = options.projectName;
const projectDescription = options.projectDescription;
const projectVersion = options.projectVersion || '1.0.0';
const authorName = options.authorName || '';
console.log('===== DEBUG: INITIALIZE PROJECT OPTIONS RECEIVED =====');
console.log('Full options object:', JSON.stringify(options));
console.log('options.yes:', options.yes);
console.log('options.name:', options.name);
console.log('==================================================');
// Determine if we should skip prompts based on the passed options
const skipPrompts = options.yes || (options.name && options.description);
console.log('Skip prompts determined:', skipPrompts);
if (skipPrompts) {
console.log('SKIPPING PROMPTS - Using defaults or provided values');
// Use provided options or defaults
const projectName = options.name || 'task-master-project';
const projectDescription = options.description || 'A project managed with Task Master AI';
const projectVersion = options.version || '0.1.0'; // Default from commands.js or here
const authorName = options.author || 'Vibe coder'; // Default if not provided
const dryRun = options.dryRun || false;
const skipInstall = options.skipInstall || false;
const addAliases = options.addAliases || false;
const addAliases = options.aliases || false;
if (dryRun) {
log('info', 'DRY RUN MODE: No files will be modified');
log(
'info',
`Would initialize project: ${projectName} (${projectVersion})`
);
log('info', `Would initialize project: ${projectName} (${projectVersion})`);
log('info', `Description: ${projectDescription}`);
log('info', `Author: ${authorName || 'Not specified'}`);
log('info', 'Would create/update necessary project files');
@@ -458,6 +427,7 @@ async function initializeProject(options = {}) {
};
}
// Create structure using determined values
createProjectStructure(
projectName,
projectDescription,
@@ -466,120 +436,88 @@ async function initializeProject(options = {}) {
skipInstall,
addAliases
);
return {
projectName,
projectDescription,
projectVersion,
authorName
};
}
} else {
// Prompting logic (only runs if skipPrompts is false)
log('info', 'Required options not provided, proceeding with prompts.');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Otherwise, prompt the user for input
// Create readline interface only when needed
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
try {
// Prompt user for input...
const projectName = await promptQuestion(rl, chalk.cyan('Enter project name: '));
const projectDescription = await promptQuestion(rl, chalk.cyan('Enter project description: '));
const projectVersionInput = await promptQuestion(rl, chalk.cyan('Enter project version (default: 1.0.0): ')); // Use a default for prompt
const authorName = await promptQuestion(rl, chalk.cyan('Enter your name: '));
const addAliasesInput = await promptQuestion(rl, chalk.cyan('Add shell aliases for task-master? (Y/n): '));
const addAliasesPrompted = addAliasesInput.trim().toLowerCase() !== 'n';
const projectVersion = projectVersionInput.trim() ? projectVersionInput : '1.0.0';
try {
const projectName = await promptQuestion(
rl,
chalk.cyan('Enter project name: ')
);
const projectDescription = await promptQuestion(
rl,
chalk.cyan('Enter project description: ')
);
const projectVersionInput = await promptQuestion(
rl,
chalk.cyan('Enter project version (default: 1.0.0): ')
);
const authorName = await promptQuestion(
rl,
chalk.cyan('Enter your name: ')
);
// Confirm settings...
console.log('\nProject settings:');
console.log(chalk.blue('Name:'), chalk.white(projectName));
console.log(chalk.blue('Description:'), chalk.white(projectDescription));
console.log(chalk.blue('Version:'), chalk.white(projectVersion));
console.log(
chalk.blue('Author:'),
chalk.white(authorName || 'Not specified')
);
console.log(
chalk.blue('Add shell aliases (so you can use "tm" instead of "task-master"):'),
chalk.white(addAliasesPrompted ? 'Yes' : 'No')
);
// Ask about shell aliases
const addAliasesInput = await promptQuestion(
rl,
chalk.cyan('Add shell aliases for task-master? (Y/n): ')
);
const addAliases = addAliasesInput.trim().toLowerCase() !== 'n';
const confirmInput = await promptQuestion(rl, chalk.yellow('\nDo you want to continue with these settings? (Y/n): '));
const shouldContinue = confirmInput.trim().toLowerCase() !== 'n';
rl.close();
// Set default version if not provided
const projectVersion = projectVersionInput.trim()
? projectVersionInput
: '1.0.0';
// Confirm settings
console.log('\nProject settings:');
console.log(chalk.blue('Name:'), chalk.white(projectName));
console.log(chalk.blue('Description:'), chalk.white(projectDescription));
console.log(chalk.blue('Version:'), chalk.white(projectVersion));
console.log(
chalk.blue('Author:'),
chalk.white(authorName || 'Not specified')
);
console.log(
chalk.blue('Add shell aliases:'),
chalk.white(addAliases ? 'Yes' : 'No')
);
const confirmInput = await promptQuestion(
rl,
chalk.yellow('\nDo you want to continue with these settings? (Y/n): ')
);
const shouldContinue = confirmInput.trim().toLowerCase() !== 'n';
// Close the readline interface
rl.close();
if (!shouldContinue) {
log('info', 'Project initialization cancelled by user');
return null;
}
const dryRun = options.dryRun || false;
const skipInstall = options.skipInstall || false;
if (dryRun) {
log('info', 'DRY RUN MODE: No files will be modified');
log('info', 'Would create/update necessary project files');
if (addAliases) {
log('info', 'Would add shell aliases for task-master');
if (!shouldContinue) {
log('info', 'Project initialization cancelled by user');
process.exit(0); // Exit if cancelled
return; // Added return for clarity
}
if (!skipInstall) {
log('info', 'Would install dependencies');
// Still respect dryRun/skipInstall if passed initially even when prompting
const dryRun = options.dryRun || false;
const skipInstall = options.skipInstall || false;
if (dryRun) {
log('info', 'DRY RUN MODE: No files will be modified');
log('info', `Would initialize project: ${projectName} (${projectVersion})`);
log('info', `Description: ${projectDescription}`);
log('info', `Author: ${authorName || 'Not specified'}`);
log('info', 'Would create/update necessary project files');
if (addAliasesPrompted) {
log('info', 'Would add shell aliases for task-master');
}
if (!skipInstall) {
log('info', 'Would install dependencies');
}
return {
projectName,
projectDescription,
projectVersion,
authorName,
dryRun: true
};
}
return {
// Create structure using prompted values, respecting initial options where relevant
createProjectStructure(
projectName,
projectDescription,
projectVersion,
authorName,
dryRun: true
};
skipInstall, // Use value from initial options
addAliasesPrompted // Use value from prompt
);
} catch (error) {
rl.close();
log('error', `Error during prompting: ${error.message}`); // Use log function
process.exit(1); // Exit on error during prompts
}
// Create the project structure
createProjectStructure(
projectName,
projectDescription,
projectVersion,
authorName,
skipInstall,
addAliases
);
return {
projectName,
projectDescription,
projectVersion,
authorName
};
} catch (error) {
// Make sure to close readline on error
rl.close();
throw error;
}
}
@@ -985,51 +923,5 @@ function setupMCPConfiguration(targetDir, projectName) {
log('info', 'MCP server will use the installed task-master-ai package');
}
// Run the initialization if this script is executed directly
// The original check doesn't work with npx and global commands
// if (process.argv[1] === fileURLToPath(import.meta.url)) {
// Instead, we'll always run the initialization if this file is the main module
console.log('Checking if script should run initialization...');
console.log('import.meta.url:', import.meta.url);
console.log('process.argv:', process.argv);
// Always run initialization when this file is loaded directly
// This works with both direct node execution and npx/global commands
(async function main() {
try {
console.log('Starting initialization...');
// Check if we should use the CLI options or prompt for input
if (options.yes || (options.name && options.description)) {
// When using --yes flag or providing name and description, use CLI options
await initializeProject({
projectName: options.name || 'task-master-project',
projectDescription:
options.description ||
'A task management system for AI-driven development',
projectVersion: options.version || '1.0.0',
authorName: options.author || '',
dryRun: options.dryRun || false,
skipInstall: options.skipInstall || false,
addAliases: options.aliases || false
});
} else {
// Otherwise, prompt for input normally
await initializeProject({
dryRun: options.dryRun || false,
skipInstall: options.skipInstall || false
});
}
// Process should exit naturally after completion
console.log('Initialization completed, exiting...');
process.exit(0);
} catch (error) {
console.error('Failed to initialize project:', error);
log('error', 'Failed to initialize project:', error);
process.exit(1);
}
})();
// Export functions for programmatic use
export { initializeProject, createProjectStructure, log };
// Ensure necessary functions are exported
export { initializeProject, log }; // Only export what's needed by commands.js

View File

@@ -10,8 +10,9 @@ import boxen from 'boxen';
import fs from 'fs';
import https from 'https';
import inquirer from 'inquirer';
import ora from 'ora';
import { CONFIG, log, readJSON } from './utils.js';
import { CONFIG, log, readJSON, writeJSON } from './utils.js';
import {
parsePRD,
updateTasks,
@@ -51,6 +52,8 @@ import {
stopLoadingIndicator
} from './ui.js';
import { initializeProject } from '../init.js';
/**
* Configure and register CLI commands
* @param {Object} program - Commander program instance
@@ -1368,44 +1371,6 @@ function registerCommands(programInstance) {
);
}
// init command (documentation only, implementation is in init.js)
programInstance
.command('init')
.description('Initialize a new project with Task Master structure')
.option('-n, --name <name>', 'Project name')
.option('-my_name <name>', 'Project name (alias for --name)')
.option('--my_name <name>', 'Project name (alias for --name)')
.option('-d, --description <description>', 'Project description')
.option(
'-my_description <description>',
'Project description (alias for --description)'
)
.option('-v, --version <version>', 'Project version')
.option('-my_version <version>', 'Project version (alias for --version)')
.option('-a, --author <author>', 'Author name')
.option('-y, --yes', 'Skip prompts and use default values')
.option('--skip-install', 'Skip installing dependencies')
.action(() => {
console.log(
chalk.yellow(
'The init command must be run as a standalone command: task-master init'
)
);
console.log(chalk.cyan('Example usage:'));
console.log(
chalk.white(
' task-master init -n "My Project" -d "Project description"'
)
);
console.log(
chalk.white(
' task-master init -my_name "My Project" -my_description "Project description"'
)
);
console.log(chalk.white(' task-master init -y'));
process.exit(0);
});
// remove-task command
programInstance
.command('remove-task')
@@ -1552,6 +1517,37 @@ function registerCommands(programInstance) {
}
});
// init command (Directly calls the implementation from init.js)
programInstance
.command('init')
.description('Initialize a new project with Task Master structure')
.option('-y, --yes', 'Skip prompts and use default values')
.option('-n, --name <name>', 'Project name')
.option('-d, --description <description>', 'Project description')
.option('-v, --version <version>', 'Project version', '0.1.0') // Set default here
.option('-a, --author <author>', 'Author name')
.option('--skip-install', 'Skip installing dependencies')
.option('--dry-run', 'Show what would be done without making changes')
.option('--aliases', 'Add shell aliases (tm, taskmaster)')
.action(async (cmdOptions) => {
// cmdOptions contains parsed arguments
try {
console.log('DEBUG: Running init command action in commands.js');
console.log(
'DEBUG: Options received by action:',
JSON.stringify(cmdOptions)
);
// Directly call the initializeProject function, passing the parsed options
await initializeProject(cmdOptions);
// initializeProject handles its own flow, including potential process.exit()
} catch (error) {
console.error(
chalk.red(`Error during initialization: ${error.message}`)
);
process.exit(1);
}
});
// Add more commands as needed...
return programInstance;