Installer: ask update/migrate first, skip config questions on update
Restructure the prompt flow so the update/fresh/migrate decision comes before config questions. On update, config.yaml is preserved so asking project name, output folder, IDEs etc. is unnecessary. Extract ides and root_folder from saved config for IDE setup and folder creation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8ba623f048
commit
ce4453c950
|
|
@ -27,6 +27,7 @@ class Installer {
|
|||
const { projectDir, wdsFolder, root_folder } = config;
|
||||
const wdsDir = path.join(projectDir, wdsFolder);
|
||||
const detection = config._detection || { type: 'fresh' };
|
||||
const action = config._action || 'fresh';
|
||||
|
||||
// Handle legacy _wds/ → _bmad/wds/ migration
|
||||
if (detection.type === 'legacy' && wdsFolder !== '_wds') {
|
||||
|
|
@ -47,45 +48,30 @@ class Installer {
|
|||
migrateSpinner.succeed(`Legacy _wds/ removed — installing fresh at ${wdsFolder}/`);
|
||||
}
|
||||
|
||||
// Check if already installed at target path
|
||||
if (await fs.pathExists(wdsDir)) {
|
||||
console.log(chalk.yellow(`\n ${wdsFolder}/ already exists.`));
|
||||
const { action } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'action',
|
||||
message: 'What would you like to do?',
|
||||
choices: [
|
||||
{ name: 'Update - Replace WDS files, keep config.yaml', value: 'update' },
|
||||
{ name: 'Fresh install - Remove everything and start over', value: 'fresh' },
|
||||
{ name: 'Cancel', value: 'cancel' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
if (action === 'cancel') {
|
||||
return { success: false };
|
||||
// Handle update vs fresh for existing target path
|
||||
if (action === 'update' && await fs.pathExists(wdsDir)) {
|
||||
// Preserve config.yaml during update
|
||||
const configPath = path.join(wdsDir, 'config.yaml');
|
||||
if (!config._savedConfigYaml && await fs.pathExists(configPath)) {
|
||||
config._savedConfigYaml = await fs.readFile(configPath, 'utf8');
|
||||
}
|
||||
|
||||
if (action === 'fresh') {
|
||||
const removeSpinner = ora('Removing existing WDS installation...').start();
|
||||
await fs.remove(wdsDir);
|
||||
removeSpinner.succeed('Old installation removed');
|
||||
} else if (action === 'update') {
|
||||
// Preserve config.yaml during update
|
||||
const configPath = path.join(wdsDir, 'config.yaml');
|
||||
let savedConfig = null;
|
||||
if (await fs.pathExists(configPath)) {
|
||||
savedConfig = await fs.readFile(configPath, 'utf8');
|
||||
}
|
||||
const removeSpinner = ora('Updating WDS files...').start();
|
||||
await fs.remove(wdsDir);
|
||||
removeSpinner.succeed('Old files cleared');
|
||||
} else if (action === 'fresh' && await fs.pathExists(wdsDir)) {
|
||||
const removeSpinner = ora('Removing existing WDS installation...').start();
|
||||
await fs.remove(wdsDir);
|
||||
removeSpinner.succeed('Old installation removed');
|
||||
}
|
||||
|
||||
const removeSpinner = ora('Updating WDS files...').start();
|
||||
await fs.remove(wdsDir);
|
||||
removeSpinner.succeed('Old files cleared');
|
||||
|
||||
// Will be restored after copy
|
||||
config._savedConfigYaml = savedConfig;
|
||||
}
|
||||
// On update, extract ides and root_folder from saved config
|
||||
if (action === 'update' && config._savedConfigYaml) {
|
||||
try {
|
||||
const savedData = yaml.load(config._savedConfigYaml);
|
||||
if (!config.ides && savedData.ides) config.ides = savedData.ides;
|
||||
if (!config.root_folder && savedData.output_folder) config.root_folder = savedData.output_folder;
|
||||
} catch { /* ignore parse errors, defaults will apply */ }
|
||||
}
|
||||
|
||||
// Ensure parent directory exists (for _bmad/wds/)
|
||||
|
|
|
|||
|
|
@ -58,33 +58,75 @@ class UI {
|
|||
|
||||
console.log(chalk.white(` Target: ${chalk.cyan(projectDir)}`));
|
||||
|
||||
// Handle legacy _wds/ detection
|
||||
let wdsFolder = detection.folder;
|
||||
let action = 'fresh';
|
||||
|
||||
// --- Existing installation: ask update/fresh/migrate FIRST ---
|
||||
if (detection.type === 'legacy') {
|
||||
console.log(chalk.yellow(`\n Found legacy installation at ${chalk.white(LEGACY_WDS_FOLDER + '/')}`));
|
||||
console.log(chalk.dim(` BMAD standard path is ${chalk.white(WDS_FOLDER + '/')}\n`));
|
||||
|
||||
const { migrationChoice } = await inquirer.prompt([
|
||||
const { choice } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'migrationChoice',
|
||||
name: 'choice',
|
||||
message: 'How would you like to proceed?',
|
||||
choices: [
|
||||
{ name: `Migrate to ${WDS_FOLDER}/ (recommended)`, value: 'migrate' },
|
||||
{ name: `Keep at ${LEGACY_WDS_FOLDER}/ (legacy)`, value: 'keep' },
|
||||
{ name: `Update & migrate to ${WDS_FOLDER}/ (recommended)`, value: 'migrate-update' },
|
||||
{ name: `Update at ${LEGACY_WDS_FOLDER}/ (keep legacy path)`, value: 'legacy-update' },
|
||||
{ name: 'Fresh install (remove everything and start over)', value: 'fresh' },
|
||||
{ name: 'Cancel', value: 'cancel' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
if (migrationChoice === 'keep') {
|
||||
if (choice === 'cancel') return { cancelled: true };
|
||||
|
||||
if (choice === 'migrate-update') {
|
||||
action = 'update';
|
||||
// wdsFolder stays as WDS_FOLDER (_bmad/wds)
|
||||
} else if (choice === 'legacy-update') {
|
||||
action = 'update';
|
||||
wdsFolder = LEGACY_WDS_FOLDER;
|
||||
} else {
|
||||
action = 'fresh';
|
||||
}
|
||||
// 'migrate' keeps the default WDS_FOLDER — installer.js handles the actual move
|
||||
} else if (detection.type === 'bmad') {
|
||||
console.log(chalk.dim(`\n Found existing installation at ${chalk.white(WDS_FOLDER + '/')}\n`));
|
||||
|
||||
const { choice } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'choice',
|
||||
message: 'What would you like to do?',
|
||||
choices: [
|
||||
{ name: 'Update - Replace WDS files, keep config.yaml', value: 'update' },
|
||||
{ name: 'Fresh install - Remove everything and start over', value: 'fresh' },
|
||||
{ name: 'Cancel', value: 'cancel' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
if (choice === 'cancel') return { cancelled: true };
|
||||
action = choice;
|
||||
} else {
|
||||
console.log(chalk.dim(` Agents and workflows will be installed in ${chalk.white(wdsFolder + '/')}\n`));
|
||||
}
|
||||
|
||||
// 5-question installer
|
||||
// --- Update: skip config questions, config.yaml will be preserved ---
|
||||
if (action === 'update') {
|
||||
console.log(chalk.dim(' Existing config.yaml will be preserved.\n'));
|
||||
|
||||
return {
|
||||
projectDir,
|
||||
wdsFolder,
|
||||
_detection: detection,
|
||||
_action: action,
|
||||
cancelled: false,
|
||||
};
|
||||
}
|
||||
|
||||
// --- Fresh install: ask all config questions ---
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
|
|
@ -154,6 +196,7 @@ class UI {
|
|||
...answers,
|
||||
wdsFolder,
|
||||
_detection: detection,
|
||||
_action: action,
|
||||
cancelled: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue