fix(installer): guard ExistingInstall.version and surface module.yaml errors

Guard ExistingInstall.version access with .installed check in
uninstall.js, ui.js, and installer.js to prevent throwing on
empty/partial _bmad dirs. Surface invalid module.yaml parse errors
as warnings instead of silently returning empty results.
This commit is contained in:
Alex Verkhovsky 2026-03-27 06:45:30 -06:00
parent 6ab01a4c13
commit 1735c08050
4 changed files with 6 additions and 5 deletions

View File

@ -62,7 +62,7 @@ module.exports = {
} }
const existingInstall = await installer.getStatus(projectDir); const existingInstall = await installer.getStatus(projectDir);
const version = existingInstall.version || 'unknown'; const version = existingInstall.installed ? existingInstall.version : 'unknown';
const modules = existingInstall.moduleIds.join(', '); const modules = existingInstall.moduleIds.join(', ');
const ides = existingInstall.ides.join(', '); const ides = existingInstall.ides.join(', ');

View File

@ -1360,7 +1360,7 @@ class Installer {
removed.modules = await this.uninstallModules(projectDir); removed.modules = await this.uninstallModules(projectDir);
} }
return { success: true, removed, version: existingInstall.version }; return { success: true, removed, version: existingInstall.installed ? existingInstall.version : null };
} }
/** /**

View File

@ -484,8 +484,9 @@ class OfficialModules {
try { try {
const yamlContent = await fs.readFile(moduleYamlPath, 'utf8'); const yamlContent = await fs.readFile(moduleYamlPath, 'utf8');
moduleYaml = yaml.parse(yamlContent); moduleYaml = yaml.parse(yamlContent);
} catch { } catch (error) {
return emptyResult; // Invalid YAML, skip await prompts.log.warn(`Invalid module.yaml for ${moduleName}: ${error.message}`);
return emptyResult;
} }
if (!moduleYaml || !moduleYaml.directories) { if (!moduleYaml || !moduleYaml.directories) {

View File

@ -72,7 +72,7 @@ class UI {
const { existingInstall, bmadDir } = await this.getExistingInstallation(confirmedDirectory); const { existingInstall, bmadDir } = await this.getExistingInstallation(confirmedDirectory);
const packageJsonPath = path.join(__dirname, '../../package.json'); const packageJsonPath = path.join(__dirname, '../../package.json');
const currentVersion = require(packageJsonPath).version; const currentVersion = require(packageJsonPath).version;
const installedVersion = existingInstall.version || 'unknown'; const installedVersion = existingInstall.installed ? existingInstall.version || 'unknown' : 'unknown';
// Build menu choices dynamically // Build menu choices dynamically
const choices = []; const choices = [];