From a7beab59b98c04ff3a14559ecb4b3d304b8bc328 Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Sat, 21 Mar 2026 04:43:58 -0600 Subject: [PATCH] refactor(installer): move discoverCustomModulePaths into CustomModules Rename to CustomModules.discoverPaths() and move from installer.js into custom-modules.js where it belongs. --- tools/cli/installers/lib/core/installer.js | 72 +----------------- .../installers/lib/modules/custom-modules.js | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+), 70 deletions(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 071e7dd33..697e3aa64 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -59,7 +59,7 @@ class Installer { const moduleConfigs = await this._collectConfigs(config, paths); // Custom module path discovery (will move to its own phase later) - const customModulePaths = await this._discoverCustomModulePaths(config, paths); + const customModulePaths = await this.customModules.discoverPaths(config, paths); // Wire configs into managers this.customModules.setPaths(customModulePaths); @@ -898,7 +898,7 @@ class Installer { /** * Collect configurations for official modules (core + selected). - * Custom module configs are handled separately in _discoverCustomModulePaths. + * Custom module configs are handled separately in CustomModules.discoverPaths. */ async _collectConfigs(config, paths) { // Seed core config if pre-collected from interactive UI @@ -924,74 +924,6 @@ class Installer { }); } - /** - * Discover custom module source paths from all available sources. - * This is a temporary home — will move to a dedicated custom module phase. - */ - async _discoverCustomModulePaths(config, paths) { - const customModulePaths = new Map(); - - if (config._quickUpdate) { - if (config._customModuleSources) { - for (const [moduleId, customInfo] of config._customModuleSources) { - customModulePaths.set(moduleId, customInfo.sourcePath); - } - } - return customModulePaths; - } - - // From manifest (regular updates) - if (config._isUpdate && config._existingInstall && config._existingInstall.customModules) { - for (const customModule of config._existingInstall.customModules) { - let absoluteSourcePath = customModule.sourcePath; - - if (absoluteSourcePath && absoluteSourcePath.startsWith('_config')) { - absoluteSourcePath = path.join(paths.bmadDir, absoluteSourcePath); - } else if (!absoluteSourcePath && customModule.relativePath) { - absoluteSourcePath = path.resolve(paths.projectRoot, customModule.relativePath); - } else if (absoluteSourcePath && !path.isAbsolute(absoluteSourcePath)) { - absoluteSourcePath = path.resolve(absoluteSourcePath); - } - - if (absoluteSourcePath) { - customModulePaths.set(customModule.id, absoluteSourcePath); - } - } - } - - // From UI: selectedFiles - if (config.customContent && config.customContent.selected && config.customContent.selectedFiles) { - const customHandler = new CustomHandler(); - for (const customFile of config.customContent.selectedFiles) { - const customInfo = await customHandler.getCustomInfo(customFile, paths.projectRoot); - if (customInfo && customInfo.id) { - customModulePaths.set(customInfo.id, customInfo.path); - } - } - } - - // From UI: sources - if (config.customContent && config.customContent.sources) { - for (const source of config.customContent.sources) { - customModulePaths.set(source.id, source.path); - } - } - - // From UI: cachedModules - if (config.customContent && config.customContent.cachedModules) { - const selectedCachedIds = config.customContent.selectedCachedModules || []; - const shouldIncludeAll = selectedCachedIds.length === 0 && config.customContent.selected; - - for (const cachedModule of config.customContent.cachedModules) { - if (cachedModule.id && cachedModule.cachePath && (shouldIncludeAll || selectedCachedIds.includes(cachedModule.id))) { - customModulePaths.set(cachedModule.id, cachedModule.cachePath); - } - } - } - - return customModulePaths; - } - /** * Install official (non-custom) modules. * @param {Object} config - Installation configuration diff --git a/tools/cli/installers/lib/modules/custom-modules.js b/tools/cli/installers/lib/modules/custom-modules.js index 4832c4b69..b8ac09930 100644 --- a/tools/cli/installers/lib/modules/custom-modules.js +++ b/tools/cli/installers/lib/modules/custom-modules.js @@ -1,3 +1,6 @@ +const path = require('node:path'); +const { CustomHandler } = require('../custom-handler'); + class CustomModules { constructor() { this.paths = new Map(); @@ -18,6 +21,76 @@ class CustomModules { set(moduleId, sourcePath) { this.paths.set(moduleId, sourcePath); } + + /** + * Discover custom module source paths from all available sources. + * @param {Object} config - Installation configuration + * @param {Object} paths - InstallPaths instance + * @returns {Map} Map of module ID to source path + */ + async discoverPaths(config, paths) { + const result = new Map(); + + if (config._quickUpdate) { + if (config._customModuleSources) { + for (const [moduleId, customInfo] of config._customModuleSources) { + result.set(moduleId, customInfo.sourcePath); + } + } + return result; + } + + // From manifest (regular updates) + if (config._isUpdate && config._existingInstall && config._existingInstall.customModules) { + for (const customModule of config._existingInstall.customModules) { + let absoluteSourcePath = customModule.sourcePath; + + if (absoluteSourcePath && absoluteSourcePath.startsWith('_config')) { + absoluteSourcePath = path.join(paths.bmadDir, absoluteSourcePath); + } else if (!absoluteSourcePath && customModule.relativePath) { + absoluteSourcePath = path.resolve(paths.projectRoot, customModule.relativePath); + } else if (absoluteSourcePath && !path.isAbsolute(absoluteSourcePath)) { + absoluteSourcePath = path.resolve(absoluteSourcePath); + } + + if (absoluteSourcePath) { + result.set(customModule.id, absoluteSourcePath); + } + } + } + + // From UI: selectedFiles + if (config.customContent && config.customContent.selected && config.customContent.selectedFiles) { + const customHandler = new CustomHandler(); + for (const customFile of config.customContent.selectedFiles) { + const customInfo = await customHandler.getCustomInfo(customFile, paths.projectRoot); + if (customInfo && customInfo.id) { + result.set(customInfo.id, customInfo.path); + } + } + } + + // From UI: sources + if (config.customContent && config.customContent.sources) { + for (const source of config.customContent.sources) { + result.set(source.id, source.path); + } + } + + // From UI: cachedModules + if (config.customContent && config.customContent.cachedModules) { + const selectedCachedIds = config.customContent.selectedCachedModules || []; + const shouldIncludeAll = selectedCachedIds.length === 0 && config.customContent.selected; + + for (const cachedModule of config.customContent.cachedModules) { + if (cachedModule.id && cachedModule.cachePath && (shouldIncludeAll || selectedCachedIds.includes(cachedModule.id))) { + result.set(cachedModule.id, cachedModule.cachePath); + } + } + } + + return result; + } } module.exports = { CustomModules };