Fix installer upgrade issues from v4 to v6. and v6 custom files will no longer be lost (modified ones will though for now still)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<!-- Powered by BMAD-CORE™ -->
|
||||
<!-- Agent Manifest - Generated during BMAD installation -->
|
||||
<!-- This file contains a summary of all installed agents for quick reference -->
|
||||
<manifest id="bmad/_cfg/agent-party.xml" version="1.0" generated="2025-10-01T00:22:43.657Z">
|
||||
<manifest id="bmad/_cfg/agent-party.xml" version="1.0" generated="2025-10-01T00:47:33.050Z">
|
||||
<description>
|
||||
Complete roster of installed BMAD agents with summarized personas for efficient multi-agent orchestration.
|
||||
Used by party-mode and other multi-agent coordination features.
|
||||
@@ -164,6 +164,6 @@
|
||||
<statistics>
|
||||
<total_agents>18</total_agents>
|
||||
<modules>bmm, cis, core, custom</modules>
|
||||
<last_updated>2025-10-01T00:22:43.657Z</last_updated>
|
||||
<last_updated>2025-10-01T00:47:33.050Z</last_updated>
|
||||
</statistics>
|
||||
</manifest>
|
||||
@@ -1,11 +1,11 @@
|
||||
# BMAD Manifest
|
||||
# Generated: 2025-10-01T00:22:43.703Z
|
||||
# Generated: 2025-10-01T00:47:33.096Z
|
||||
|
||||
## Installation Info
|
||||
Property,Value
|
||||
Version,6.0.0-alpha.0
|
||||
InstallDate,2025-10-01T00:22:43.690Z
|
||||
LastUpdated,2025-10-01T00:22:43.703Z
|
||||
InstallDate,2025-10-01T00:47:33.083Z
|
||||
LastUpdated,2025-10-01T00:47:33.096Z
|
||||
|
||||
## Modules
|
||||
Name,Version,ShortTitle
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
installation:
|
||||
version: 6.0.0-alpha.0
|
||||
installDate: "2025-10-01T00:22:43.664Z"
|
||||
lastUpdated: "2025-10-01T00:22:43.664Z"
|
||||
installDate: "2025-10-01T00:47:33.058Z"
|
||||
lastUpdated: "2025-10-01T00:47:33.058Z"
|
||||
modules:
|
||||
- name: core
|
||||
version: ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# BMB Module Configuration
|
||||
# Generated by BMAD installer
|
||||
# Version: 6.0.0-alpha.0
|
||||
# Date: 2025-10-01T00:22:43.652Z
|
||||
# Date: 2025-10-01T00:47:33.045Z
|
||||
|
||||
# Core Configuration Values
|
||||
user_name: BMad
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# BMM Module Configuration
|
||||
# Generated by BMAD installer
|
||||
# Version: 6.0.0-alpha.0
|
||||
# Date: 2025-10-01T00:22:43.653Z
|
||||
# Date: 2025-10-01T00:47:33.046Z
|
||||
|
||||
project_name: My Project
|
||||
tech_docs: "{project-root}/docs"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# CIS Module Configuration
|
||||
# Generated by BMAD installer
|
||||
# Version: 6.0.0-alpha.0
|
||||
# Date: 2025-10-01T00:22:43.653Z
|
||||
# Date: 2025-10-01T00:47:33.046Z
|
||||
|
||||
# Core Configuration Values
|
||||
user_name: BMad
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# CORE Module Configuration
|
||||
# Generated by BMAD installer
|
||||
# Version: 6.0.0-alpha.0
|
||||
# Date: 2025-10-01T00:22:43.654Z
|
||||
# Date: 2025-10-01T00:47:33.046Z
|
||||
|
||||
user_name: BMad
|
||||
communication_language: English
|
||||
|
||||
@@ -185,12 +185,61 @@ class Installer {
|
||||
console.log(chalk.dim(` Location: ${bmadDir}`));
|
||||
console.log(chalk.dim(` Version: ${existingInstall.version}`));
|
||||
|
||||
// TODO: Handle update scenario
|
||||
const { action } = await this.promptUpdateAction();
|
||||
if (action === 'cancel') {
|
||||
console.log('Installation cancelled.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'reinstall') {
|
||||
// Warn about destructive operation
|
||||
console.log(chalk.red.bold('\n⚠️ WARNING: This is a destructive operation!'));
|
||||
console.log(chalk.red('All custom files and modifications in the bmad directory will be lost.'));
|
||||
|
||||
const inquirer = require('inquirer');
|
||||
const { confirmReinstall } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirmReinstall',
|
||||
message: chalk.yellow('Are you sure you want to delete and reinstall?'),
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmReinstall) {
|
||||
console.log('Installation cancelled.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove existing installation
|
||||
await fs.remove(bmadDir);
|
||||
console.log(chalk.green('✓ Removed existing installation\n'));
|
||||
} else if (action === 'update') {
|
||||
// Store that we're updating for later processing
|
||||
config._isUpdate = true;
|
||||
config._existingInstall = existingInstall;
|
||||
|
||||
// Detect custom files BEFORE updating (compare current files vs manifest)
|
||||
const existingManifest = await this.manifest.read(bmadDir);
|
||||
config._customFiles = await this.detectCustomFiles(bmadDir, existingManifest);
|
||||
|
||||
// If there are custom files, back them up temporarily
|
||||
if (config._customFiles.length > 0) {
|
||||
const tempBackupDir = path.join(projectDir, '.bmad-custom-backup-temp');
|
||||
await fs.ensureDir(tempBackupDir);
|
||||
|
||||
spinner.start(`Backing up ${config._customFiles.length} custom files...`);
|
||||
for (const customFile of config._customFiles) {
|
||||
const relativePath = path.relative(bmadDir, customFile);
|
||||
const backupPath = path.join(tempBackupDir, relativePath);
|
||||
await fs.ensureDir(path.dirname(backupPath));
|
||||
await fs.copy(customFile, backupPath);
|
||||
}
|
||||
spinner.succeed(`Backed up ${config._customFiles.length} custom files`);
|
||||
|
||||
config._tempBackupDir = tempBackupDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create bmad directory structure
|
||||
@@ -352,8 +401,42 @@ class Installer {
|
||||
);
|
||||
spinner.succeed(`Manifest created (${manifestResult.filesTracked} files tracked)`);
|
||||
|
||||
// If this was an update, restore custom files
|
||||
let customFiles = [];
|
||||
if (config._isUpdate && config._customFiles && config._customFiles.length > 0) {
|
||||
spinner.start(`Restoring ${config._customFiles.length} custom files...`);
|
||||
|
||||
for (const originalPath of config._customFiles) {
|
||||
const relativePath = path.relative(bmadDir, originalPath);
|
||||
const backupPath = path.join(config._tempBackupDir, relativePath);
|
||||
|
||||
if (await fs.pathExists(backupPath)) {
|
||||
await fs.ensureDir(path.dirname(originalPath));
|
||||
await fs.copy(backupPath, originalPath, { overwrite: true });
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up temp backup
|
||||
if (config._tempBackupDir && (await fs.pathExists(config._tempBackupDir))) {
|
||||
await fs.remove(config._tempBackupDir);
|
||||
}
|
||||
|
||||
spinner.succeed(`Restored ${config._customFiles.length} custom files`);
|
||||
customFiles = config._customFiles;
|
||||
}
|
||||
|
||||
spinner.stop();
|
||||
|
||||
// Report custom files if any were found
|
||||
if (customFiles.length > 0) {
|
||||
console.log(chalk.cyan(`\n📁 Custom files preserved: ${customFiles.length}`));
|
||||
console.log(chalk.dim('The following custom files were found and restored:\n'));
|
||||
for (const file of customFiles) {
|
||||
console.log(chalk.dim(` - ${path.relative(bmadDir, file)}`));
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Display completion message
|
||||
const { UI } = require('../../../lib/ui');
|
||||
const ui = new UI();
|
||||
@@ -361,6 +444,7 @@ class Installer {
|
||||
path: bmadDir,
|
||||
modules: config.modules,
|
||||
ides: config.ides,
|
||||
customFiles: customFiles.length > 0 ? customFiles : undefined,
|
||||
});
|
||||
|
||||
return { success: true, path: bmadDir, modules: config.modules, ides: config.ides };
|
||||
@@ -922,6 +1006,59 @@ class Installer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect custom files that were not installed by the installer
|
||||
* @param {string} bmadDir - BMAD installation directory
|
||||
* @param {Object} existingManifest - Previous installation manifest
|
||||
* @returns {Array} List of custom files found
|
||||
*/
|
||||
async detectCustomFiles(bmadDir, existingManifest) {
|
||||
const customFiles = [];
|
||||
|
||||
// Build set of previously installed files from manifest
|
||||
const installedSet = new Set();
|
||||
if (existingManifest && existingManifest.files) {
|
||||
for (const fileEntry of existingManifest.files) {
|
||||
if (fileEntry.file) {
|
||||
// Files in manifest are stored as relative paths starting with 'bmad/'
|
||||
// Convert to absolute path
|
||||
const relativePath = fileEntry.file.startsWith('bmad/') ? fileEntry.file.slice(5) : fileEntry.file;
|
||||
const absolutePath = path.join(bmadDir, relativePath);
|
||||
installedSet.add(path.normalize(absolutePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively scan bmadDir for all files
|
||||
const scanDirectory = async (dir) => {
|
||||
try {
|
||||
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// Skip certain directories
|
||||
if (entry.name === 'node_modules' || entry.name === '.git') {
|
||||
continue;
|
||||
}
|
||||
await scanDirectory(fullPath);
|
||||
} else if (entry.isFile()) {
|
||||
const normalizedPath = path.normalize(fullPath);
|
||||
// If file is not in the previous manifest, it's custom
|
||||
if (!installedSet.has(normalizedPath)) {
|
||||
customFiles.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors scanning directories
|
||||
}
|
||||
};
|
||||
|
||||
await scanDirectory(bmadDir);
|
||||
return customFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private: Create agent configuration files
|
||||
* @param {string} bmadDir - BMAD installation directory
|
||||
|
||||
Reference in New Issue
Block a user