Call rules interactive setup during init (#833)

This commit is contained in:
Joe Danziger
2025-06-20 16:05:25 -04:00
committed by GitHub
parent 727f1ec4eb
commit d54f23e8a9
4 changed files with 111 additions and 24 deletions

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
Call rules interactive setup during init

View File

@@ -352,10 +352,30 @@ async function initializeProject(options = {}) {
// console.log('Skip prompts determined:', skipPrompts); // console.log('Skip prompts determined:', skipPrompts);
// } // }
const selectedRuleProfiles = let selectedRuleProfiles;
options.rules && Array.isArray(options.rules) && options.rules.length > 0 if (options.rulesExplicitlyProvided) {
? options.rules // If --rules flag was used, always respect it.
: RULE_PROFILES; // Default to all profiles 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 (skipPrompts) {
if (!isSilentMode()) { if (!isSilentMode()) {
@@ -492,16 +512,6 @@ async function initializeProject(options = {}) {
'info', 'info',
`Using rule profiles provided via command line: ${selectedRuleProfiles.join(', ')}` `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; const dryRun = options.dryRun || false;
@@ -541,7 +551,9 @@ async function initializeProject(options = {}) {
); );
rl.close(); rl.close();
} catch (error) { } catch (error) {
if (rl) {
rl.close(); rl.close();
}
log('error', `Error during initialization process: ${error.message}`); log('error', `Error during initialization process: ${error.message}`);
process.exit(1); process.exit(1);
} }
@@ -564,7 +576,7 @@ function createProjectStructure(
storeTasksInGit, storeTasksInGit,
dryRun, dryRun,
options, options,
selectedRuleProfiles = RULE_PROFILES // Default to all rule profiles selectedRuleProfiles = RULE_PROFILES
) { ) {
const targetDir = process.cwd(); const targetDir = process.cwd();
log('info', `Initializing project in ${targetDir}`); log('info', `Initializing project in ${targetDir}`);
@@ -665,11 +677,14 @@ function createProjectStructure(
log('warn', 'Git not available, skipping repository initialization'); log('warn', 'Git not available, skipping repository initialization');
} }
// Generate profile rules from assets/rules // Only run the manual transformer if rules were provided via flags.
log('info', 'Generating profile rules from assets/rules...'); // 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) { for (const profileName of selectedRuleProfiles) {
_processSingleProfile(profileName); _processSingleProfile(profileName);
} }
}
// Add shell aliases if requested // Add shell aliases if requested
if (addAliases) { if (addAliases) {
@@ -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 === // === Add Model Configuration Step ===
if (!isSilentMode() && !dryRun && !options?.yes) { if (!isSilentMode() && !dryRun && !options?.yes) {
console.log( console.log(

View File

@@ -3828,7 +3828,26 @@ Examples:
if (options[RULES_SETUP_ACTION]) { if (options[RULES_SETUP_ACTION]) {
// Run interactive rules setup ONLY (no project init) // Run interactive rules setup ONLY (no project init)
const selectedRuleProfiles = await runInteractiveProfilesSetup(); 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)) { if (!isValidProfile(profile)) {
console.warn( console.warn(
`Rule profile for "${profile}" not found. Valid profiles: ${RULE_PROFILES.join(', ')}. Skipping.` `Rule profile for "${profile}" not found. Valid profiles: ${RULE_PROFILES.join(', ')}. Skipping.`
@@ -3836,16 +3855,20 @@ Examples:
continue; continue;
} }
const profileConfig = getRulesProfile(profile); const profileConfig = getRulesProfile(profile);
const addResult = convertAllRulesToProfileRules( const addResult = convertAllRulesToProfileRules(
projectDir, projectDir,
profileConfig profileConfig
); );
if (typeof profileConfig.onAddRulesProfile === 'function') {
profileConfig.onAddRulesProfile(projectDir);
}
console.log(chalk.green(generateProfileSummary(profile, addResult))); console.log(chalk.green(generateProfileSummary(profile, addResult)));
} }
console.log(
chalk.green(
`\nCompleted installation of all ${selectedRuleProfiles.length} profile(s).`
)
);
return; return;
} }

View File

@@ -206,6 +206,7 @@ export function convertAllRulesToProfileRules(projectDir, profile) {
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
const assetsDir = path.join(__dirname, '..', '..', 'assets'); const assetsDir = path.join(__dirname, '..', '..', 'assets');
if (typeof profile.onPostConvertRulesProfile === 'function') { if (typeof profile.onPostConvertRulesProfile === 'function') {
profile.onPostConvertRulesProfile(projectDir, assetsDir); profile.onPostConvertRulesProfile(projectDir, assetsDir);
} }