refactor(installer): extract _prepareUpdateState to unify update branches

Both the regular update and quick-update branches of install() shared
identical sequences: set update flags, detect custom/modified files,
scan cached custom modules, and back up user files. Extract into a
single _prepareUpdateState method called by both branches. Core config
preservation is included (harmless no-op for quick-update which already
has core config).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Verkhovsky 2026-03-21 20:05:55 -06:00
parent 206984f3db
commit 1a519b9748
1 changed files with 46 additions and 49 deletions

View File

@ -91,10 +91,6 @@ class Installer {
} }
if (action === 'update') { if (action === 'update') {
// Store that we're updating for later processing
customConfig._isUpdate = true;
customConfig._existingInstall = existingInstall;
// Detect modules that were previously installed but are NOT in the new selection (to be removed) // Detect modules that were previously installed but are NOT in the new selection (to be removed)
const previouslyInstalledModules = new Set(existingInstall.modules.map((m) => m.id)); const previouslyInstalledModules = new Set(existingInstall.modules.map((m) => m.id));
const newlySelectedModules = new Set(config.modules || []); const newlySelectedModules = new Set(config.modules || []);
@ -157,55 +153,12 @@ class Installer {
} }
} }
// Detect custom and modified files BEFORE updating (compare current files vs files-manifest.csv) await this._prepareUpdateState(paths, config, customConfig, existingInstall, spinner);
const existingFilesManifest = await this.readFilesManifest(paths.bmadDir);
const { customFiles, modifiedFiles } = await this.detectCustomFiles(paths.bmadDir, existingFilesManifest);
customConfig._customFiles = customFiles;
customConfig._modifiedFiles = modifiedFiles;
// Preserve existing core configuration during updates
// Read the current core config.yaml to maintain user's settings
const coreConfigPath = paths.moduleConfig('core');
if ((await fs.pathExists(coreConfigPath)) && (!config.coreConfig || Object.keys(config.coreConfig).length === 0)) {
try {
const yaml = require('yaml');
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
const existingCoreConfig = yaml.parse(coreConfigContent);
// Preserve through the installation
config.coreConfig = existingCoreConfig;
customConfig.coreConfig = existingCoreConfig;
this.configCollector.collectedConfig.core = existingCoreConfig;
} catch (error) {
await prompts.log.warn(`Warning: Could not read existing core config: ${error.message}`);
}
}
await this._scanCachedCustomModules(paths);
const backupDirs = await this._backupUserFiles(paths, customFiles, modifiedFiles, spinner);
customConfig._tempBackupDir = backupDirs.tempBackupDir;
customConfig._tempModifiedBackupDir = backupDirs.tempModifiedBackupDir;
} }
} else if (existingInstall.installed && config.isQuickUpdate()) { } else if (existingInstall.installed && config.isQuickUpdate()) {
// Quick update mode - automatically treat as update without prompting // Quick update mode - automatically treat as update without prompting
spinner.message('Preparing quick update...'); spinner.message('Preparing quick update...');
customConfig._isUpdate = true; await this._prepareUpdateState(paths, config, customConfig, existingInstall, spinner);
customConfig._existingInstall = existingInstall;
// Detect custom and modified files BEFORE updating
const existingFilesManifest = await this.readFilesManifest(paths.bmadDir);
const { customFiles, modifiedFiles } = await this.detectCustomFiles(paths.bmadDir, existingFilesManifest);
customConfig._customFiles = customFiles;
customConfig._modifiedFiles = modifiedFiles;
await this._scanCachedCustomModules(paths);
const backupDirs = await this._backupUserFiles(paths, customFiles, modifiedFiles, spinner);
customConfig._tempBackupDir = backupDirs.tempBackupDir;
customConfig._tempModifiedBackupDir = backupDirs.tempModifiedBackupDir;
} }
// Now collect tool configurations after we know if it's a reinstall // Now collect tool configurations after we know if it's a reinstall
@ -814,6 +767,50 @@ class Installer {
} }
} }
/**
* Common update preparation: detect files, preserve core config, scan cache, back up.
* Used by both regular update and quick-update branches.
* @param {Object} paths - InstallPaths instance
* @param {Object} config - Clean config (may have coreConfig updated)
* @param {Object} customConfig - Full config bag (mutated with update state)
* @param {Object} existingInstall - Detection result from detector.detect()
* @param {Object} spinner - Spinner instance for progress display
*/
async _prepareUpdateState(paths, config, customConfig, existingInstall, spinner) {
customConfig._isUpdate = true;
customConfig._existingInstall = existingInstall;
// Detect custom and modified files BEFORE updating (compare current files vs files-manifest.csv)
const existingFilesManifest = await this.readFilesManifest(paths.bmadDir);
const { customFiles, modifiedFiles } = await this.detectCustomFiles(paths.bmadDir, existingFilesManifest);
customConfig._customFiles = customFiles;
customConfig._modifiedFiles = modifiedFiles;
// Preserve existing core configuration during updates
// (no-op for quick-update which already has core config from collectModuleConfigQuick)
const coreConfigPath = paths.moduleConfig('core');
if ((await fs.pathExists(coreConfigPath)) && (!config.coreConfig || Object.keys(config.coreConfig).length === 0)) {
try {
const yaml = require('yaml');
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
const existingCoreConfig = yaml.parse(coreConfigContent);
config.coreConfig = existingCoreConfig;
customConfig.coreConfig = existingCoreConfig;
this.configCollector.collectedConfig.core = existingCoreConfig;
} catch (error) {
await prompts.log.warn(`Warning: Could not read existing core config: ${error.message}`);
}
}
await this._scanCachedCustomModules(paths);
const backupDirs = await this._backupUserFiles(paths, customFiles, modifiedFiles, spinner);
customConfig._tempBackupDir = backupDirs.tempBackupDir;
customConfig._tempModifiedBackupDir = backupDirs.tempModifiedBackupDir;
}
/** /**
* Back up custom and modified files to temp directories before overwriting. * Back up custom and modified files to temp directories before overwriting.
* Returns the temp directory paths (or undefined if no files to back up). * Returns the temp directory paths (or undefined if no files to back up).