From cf2c06697a0b5b952fb6ca4b3c923e9892604d08 Mon Sep 17 00:00:00 2001 From: Joe Danziger Date: Fri, 20 Jun 2025 16:05:25 -0400 Subject: [PATCH] Call rules interactive setup during init (#833) --- .changeset/icy-dryers-hunt.md | 5 ++ scripts/init.js | 98 ++++++++++++++++++++++++++++------- scripts/modules/commands.js | 31 +++++++++-- src/utils/rule-transformer.js | 1 + 4 files changed, 111 insertions(+), 24 deletions(-) create mode 100644 .changeset/icy-dryers-hunt.md diff --git a/.changeset/icy-dryers-hunt.md b/.changeset/icy-dryers-hunt.md new file mode 100644 index 00000000..0be2f1e0 --- /dev/null +++ b/.changeset/icy-dryers-hunt.md @@ -0,0 +1,5 @@ +--- +"task-master-ai": patch +--- + +Call rules interactive setup during init diff --git a/scripts/init.js b/scripts/init.js index 3e8434d0..f168429a 100755 --- a/scripts/init.js +++ b/scripts/init.js @@ -352,10 +352,30 @@ async function initializeProject(options = {}) { // console.log('Skip prompts determined:', skipPrompts); // } - const selectedRuleProfiles = - options.rules && Array.isArray(options.rules) && options.rules.length > 0 - ? options.rules - : RULE_PROFILES; // Default to all profiles + let selectedRuleProfiles; + if (options.rulesExplicitlyProvided) { + // If --rules flag was used, always respect it. + log( + 'info', + `Using rule profiles provided via command line: ${options.rules.join(', ')}` + ); + selectedRuleProfiles = options.rules; + } else if (skipPrompts) { + // If non-interactive (e.g., --yes) and no rules specified, default to ALL. + log( + 'info', + `No rules specified in non-interactive mode, defaulting to all profiles.` + ); + selectedRuleProfiles = RULE_PROFILES; + } else { + // If interactive and no rules specified, default to NONE. + // The 'rules --setup' wizard will handle selection. + log( + 'info', + 'No rules specified; interactive setup will be launched to select profiles.' + ); + selectedRuleProfiles = []; + } if (skipPrompts) { if (!isSilentMode()) { @@ -492,16 +512,6 @@ async function initializeProject(options = {}) { 'info', `Using rule profiles provided via command line: ${selectedRuleProfiles.join(', ')}` ); - } else { - try { - const targetDir = process.cwd(); - execSync('npx task-master rules setup', { - stdio: 'inherit', - cwd: targetDir - }); - } catch (error) { - log('error', 'Failed to run interactive rules setup:', error.message); - } } const dryRun = options.dryRun || false; @@ -541,7 +551,9 @@ async function initializeProject(options = {}) { ); rl.close(); } catch (error) { - rl.close(); + if (rl) { + rl.close(); + } log('error', `Error during initialization process: ${error.message}`); process.exit(1); } @@ -564,7 +576,7 @@ function createProjectStructure( storeTasksInGit, dryRun, options, - selectedRuleProfiles = RULE_PROFILES // Default to all rule profiles + selectedRuleProfiles = RULE_PROFILES ) { const targetDir = process.cwd(); log('info', `Initializing project in ${targetDir}`); @@ -665,10 +677,13 @@ function createProjectStructure( log('warn', 'Git not available, skipping repository initialization'); } - // Generate profile rules from assets/rules - log('info', 'Generating profile rules from assets/rules...'); - for (const profileName of selectedRuleProfiles) { - _processSingleProfile(profileName); + // Only run the manual transformer if rules were provided via flags. + // The interactive `rules --setup` wizard handles its own installation. + if (options.rulesExplicitlyProvided || options.yes) { + log('info', 'Generating profile rules from command-line flags...'); + for (const profileName of selectedRuleProfiles) { + _processSingleProfile(profileName); + } } // Add shell aliases if requested @@ -699,6 +714,49 @@ function createProjectStructure( ); } + // === Add Rule Profiles Setup Step === + if ( + !isSilentMode() && + !dryRun && + !options?.yes && + !options.rulesExplicitlyProvided + ) { + console.log( + boxen(chalk.cyan('Configuring Rule Profiles...'), { + padding: 0.5, + margin: { top: 1, bottom: 0.5 }, + borderStyle: 'round', + borderColor: 'blue' + }) + ); + log( + 'info', + 'Running interactive rules setup. Please select which rule profiles to include.' + ); + try { + // Correct command confirmed by you. + execSync('npx task-master rules --setup', { + stdio: 'inherit', + cwd: targetDir + }); + log('success', 'Rule profiles configured.'); + } catch (error) { + log('error', 'Failed to configure rule profiles:', error.message); + log('warn', 'You may need to run "task-master rules --setup" manually.'); + } + } else if (isSilentMode() || dryRun || options?.yes) { + // This branch can log why setup was skipped, similar to the model setup logic. + if (options.rulesExplicitlyProvided) { + log( + 'info', + 'Skipping interactive rules setup because --rules flag was used.' + ); + } else { + log('info', 'Skipping interactive rules setup in non-interactive mode.'); + } + } + // ===================================== + // === Add Model Configuration Step === if (!isSilentMode() && !dryRun && !options?.yes) { console.log( diff --git a/scripts/modules/commands.js b/scripts/modules/commands.js index 1904411c..23e6d1bb 100644 --- a/scripts/modules/commands.js +++ b/scripts/modules/commands.js @@ -3828,7 +3828,26 @@ Examples: if (options[RULES_SETUP_ACTION]) { // Run interactive rules setup ONLY (no project init) const selectedRuleProfiles = await runInteractiveProfilesSetup(); - for (const profile of selectedRuleProfiles) { + + if (!selectedRuleProfiles || selectedRuleProfiles.length === 0) { + console.log(chalk.yellow('No profiles selected. Exiting.')); + return; + } + + console.log( + chalk.blue( + `Installing ${selectedRuleProfiles.length} selected profile(s)...` + ) + ); + + for (let i = 0; i < selectedRuleProfiles.length; i++) { + const profile = selectedRuleProfiles[i]; + console.log( + chalk.blue( + `Processing profile ${i + 1}/${selectedRuleProfiles.length}: ${profile}...` + ) + ); + if (!isValidProfile(profile)) { console.warn( `Rule profile for "${profile}" not found. Valid profiles: ${RULE_PROFILES.join(', ')}. Skipping.` @@ -3836,16 +3855,20 @@ Examples: continue; } const profileConfig = getRulesProfile(profile); + const addResult = convertAllRulesToProfileRules( projectDir, profileConfig ); - if (typeof profileConfig.onAddRulesProfile === 'function') { - profileConfig.onAddRulesProfile(projectDir); - } console.log(chalk.green(generateProfileSummary(profile, addResult))); } + + console.log( + chalk.green( + `\nCompleted installation of all ${selectedRuleProfiles.length} profile(s).` + ) + ); return; } diff --git a/src/utils/rule-transformer.js b/src/utils/rule-transformer.js index 70df8e20..d41a5505 100644 --- a/src/utils/rule-transformer.js +++ b/src/utils/rule-transformer.js @@ -206,6 +206,7 @@ export function convertAllRulesToProfileRules(projectDir, profile) { const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const assetsDir = path.join(__dirname, '..', '..', 'assets'); + if (typeof profile.onPostConvertRulesProfile === 'function') { profile.onPostConvertRulesProfile(projectDir, assetsDir); }