From 2c4c2d9717ad9552d05c18e8852f3af7f3b202af Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Mon, 15 Dec 2025 23:53:26 +0800 Subject: [PATCH] reduce installer log output --- tools/cli/installers/lib/core/installer.js | 271 ++++++-------------- tools/cli/installers/lib/modules/manager.js | 121 +-------- tools/cli/lib/ui.js | 160 +++++++++++- 3 files changed, 245 insertions(+), 307 deletions(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 6cbc1635..957d5f94 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -439,6 +439,33 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: } } } else { + // For regular updates (modify flow), check manifest for custom module sources + if (config._isUpdate && config._existingInstall && config._existingInstall.customModules) { + for (const customModule of config._existingInstall.customModules) { + // Ensure we have an absolute sourcePath + let absoluteSourcePath = customModule.sourcePath; + + // Check if sourcePath is a cache-relative path (starts with _config) + if (absoluteSourcePath && absoluteSourcePath.startsWith('_config')) { + // Convert cache-relative path to absolute path + absoluteSourcePath = path.join(bmadDir, absoluteSourcePath); + } + // If no sourcePath but we have relativePath, convert it + else if (!absoluteSourcePath && customModule.relativePath) { + // relativePath is relative to the project root (parent of bmad dir) + absoluteSourcePath = path.resolve(projectDir, customModule.relativePath); + } + // Ensure sourcePath is absolute for anything else + else if (absoluteSourcePath && !path.isAbsolute(absoluteSourcePath)) { + absoluteSourcePath = path.resolve(absoluteSourcePath); + } + + if (absoluteSourcePath) { + customModulePaths.set(customModule.id, absoluteSourcePath); + } + } + } + // Build custom module paths map from customContent // Handle selectedFiles (from existing install path or manual directory input) @@ -589,20 +616,39 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: // Detect custom and modified files BEFORE updating (compare current files vs files-manifest.csv) const existingFilesManifest = await this.readFilesManifest(bmadDir); - console.log(chalk.dim(`DEBUG: Read ${existingFilesManifest.length} files from manifest`)); - console.log(chalk.dim(`DEBUG: Manifest has hashes: ${existingFilesManifest.some((f) => f.hash)}`)); - const { customFiles, modifiedFiles } = await this.detectCustomFiles(bmadDir, existingFilesManifest); - console.log(chalk.dim(`DEBUG: Found ${customFiles.length} custom files, ${modifiedFiles.length} modified files`)); - if (modifiedFiles.length > 0) { - console.log(chalk.yellow('DEBUG: Modified files:')); - for (const f of modifiedFiles) console.log(chalk.dim(` - ${f.path}`)); - } - config._customFiles = customFiles; config._modifiedFiles = modifiedFiles; + // Also check cache directory for custom modules (like quick update does) + const cacheDir = path.join(bmadDir, '_config', 'custom'); + if (await fs.pathExists(cacheDir)) { + const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true }); + + for (const cachedModule of cachedModules) { + if (cachedModule.isDirectory()) { + const moduleId = cachedModule.name; + + // Skip if we already have this module from manifest + if (customModulePaths.has(moduleId)) { + continue; + } + + const cachedPath = path.join(cacheDir, moduleId); + + // Check if this is actually a custom module (has module.yaml) + const moduleYamlPath = path.join(cachedPath, 'module.yaml'); + if (await fs.pathExists(moduleYamlPath)) { + customModulePaths.set(moduleId, cachedPath); + } + } + } + + // Update module manager with the new custom module paths from cache + this.moduleManager.setCustomModulePaths(customModulePaths); + } + // If there are custom files, back them up temporarily if (customFiles.length > 0) { const tempBackupDir = path.join(projectDir, '_bmad-custom-backup-temp'); @@ -625,20 +671,16 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: const tempModifiedBackupDir = path.join(projectDir, '_bmad-modified-backup-temp'); await fs.ensureDir(tempModifiedBackupDir); - console.log(chalk.yellow(`\nDEBUG: Backing up ${modifiedFiles.length} modified files to temp location`)); spinner.start(`Backing up ${modifiedFiles.length} modified files...`); for (const modifiedFile of modifiedFiles) { const relativePath = path.relative(bmadDir, modifiedFile.path); const tempBackupPath = path.join(tempModifiedBackupDir, relativePath); - console.log(chalk.dim(`DEBUG: Backing up ${relativePath} to temp`)); await fs.ensureDir(path.dirname(tempBackupPath)); await fs.copy(modifiedFile.path, tempBackupPath, { overwrite: true }); } spinner.succeed(`Backed up ${modifiedFiles.length} modified files`); config._tempModifiedBackupDir = tempModifiedBackupDir; - } else { - console.log(chalk.dim('DEBUG: No modified files detected')); } } } else if (existingInstall.installed && config._quickUpdate) { @@ -654,6 +696,34 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: config._customFiles = customFiles; config._modifiedFiles = modifiedFiles; + // Also check cache directory for custom modules (like quick update does) + const cacheDir = path.join(bmadDir, '_config', 'custom'); + if (await fs.pathExists(cacheDir)) { + const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true }); + + for (const cachedModule of cachedModules) { + if (cachedModule.isDirectory()) { + const moduleId = cachedModule.name; + + // Skip if we already have this module from manifest + if (customModulePaths.has(moduleId)) { + continue; + } + + const cachedPath = path.join(cacheDir, moduleId); + + // Check if this is actually a custom module (has module.yaml) + const moduleYamlPath = path.join(cachedPath, 'module.yaml'); + if (await fs.pathExists(moduleYamlPath)) { + customModulePaths.set(moduleId, cachedPath); + } + } + } + + // Update module manager with the new custom module paths from cache + this.moduleManager.setCustomModulePaths(customModulePaths); + } + // Back up custom files if (customFiles.length > 0) { const tempBackupDir = path.join(projectDir, '_bmad-custom-backup-temp'); @@ -832,7 +902,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: // For dependency resolution, we need to pass the project root // Create a temporary module manager that knows about custom content locations const tempModuleManager = new ModuleManager({ - scanProjectForModules: true, bmadDir: bmadDir, // Pass bmadDir so we can check cache }); @@ -1057,7 +1126,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: // Pass pre-collected configuration to avoid re-prompting await this.ideManager.setup(ide, projectDir, bmadDir, { - selectedModules: config.modules || [], + selectedModules: allModules || [], preCollectedConfig: ideConfigurations[ide] || null, verbose: config.verbose, }); @@ -1184,11 +1253,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: // Report custom and modified 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 customFile of customFiles) { - const relativePath = path.relative(projectDir, customFile); - console.log(chalk.dim(` • ${relativePath}`)); - } } if (modifiedFiles.length > 0) { @@ -2184,41 +2248,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: const configuredIdes = existingInstall.ides || []; const projectRoot = path.dirname(bmadDir); - // Get custom module sources from manifest and cache + // Get custom module sources from cache const customModuleSources = new Map(); - - // First check manifest for backward compatibility - if (existingInstall.customModules) { - for (const customModule of existingInstall.customModules) { - // Ensure we have an absolute sourcePath - let absoluteSourcePath = customModule.sourcePath; - - // Check if sourcePath is a cache-relative path (starts with _config/) - if (absoluteSourcePath && absoluteSourcePath.startsWith('_config')) { - // Convert cache-relative path to absolute path - absoluteSourcePath = path.join(bmadDir, absoluteSourcePath); - } - // If no sourcePath but we have relativePath, convert it - else if (!absoluteSourcePath && customModule.relativePath) { - // relativePath is relative to the project root (parent of bmad dir) - absoluteSourcePath = path.resolve(projectRoot, customModule.relativePath); - } - // Ensure sourcePath is absolute for anything else - else if (absoluteSourcePath && !path.isAbsolute(absoluteSourcePath)) { - absoluteSourcePath = path.resolve(absoluteSourcePath); - } - - // Update the custom module object with the absolute path - const updatedModule = { - ...customModule, - sourcePath: absoluteSourcePath, - }; - - customModuleSources.set(customModule.id, updatedModule); - } - } - - // Also check cache directory for any modules not in manifest const cacheDir = path.join(bmadDir, '_config', 'custom'); if (await fs.pathExists(cacheDir)) { const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true }); @@ -2277,126 +2308,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: } } - // Check for untracked custom modules (installed but not in manifest) - const untrackedCustomModules = []; - for (const installedModule of installedModules) { - // Skip standard modules and core - const standardModuleIds = ['bmb', 'bmgd', 'bmm', 'cis', 'core']; - if (standardModuleIds.includes(installedModule)) { - continue; - } - - // Check if this installed module is not tracked in customModules - if (!customModuleSources.has(installedModule)) { - const modulePath = path.join(bmadDir, installedModule); - if (await fs.pathExists(modulePath)) { - untrackedCustomModules.push({ - id: installedModule, - name: installedModule, // We don't have the original name - path: modulePath, - untracked: true, - }); - } - } - } - - // If we found untracked custom modules, offer to track them - if (untrackedCustomModules.length > 0) { - spinner.stop(); - console.log(chalk.yellow(`\nāš ļø Found ${untrackedCustomModules.length} custom module(s) not tracked in manifest:`)); - - for (const untracked of untrackedCustomModules) { - console.log(chalk.dim(` • ${untracked.id} (installed at ${path.relative(projectRoot, untracked.path)})`)); - } - - const { trackModules } = await inquirer.prompt([ - { - type: 'confirm', - name: 'trackModules', - message: chalk.cyan('Would you like to scan for their source locations?'), - default: true, - }, - ]); - - if (trackModules) { - const { scanDirectory } = await inquirer.prompt([ - { - type: 'input', - name: 'scanDirectory', - message: 'Enter directory to scan for custom module sources (or leave blank to skip):', - default: projectRoot, - validate: async (input) => { - if (input && input.trim() !== '') { - const expandedPath = path.resolve(input.trim()); - if (!(await fs.pathExists(expandedPath))) { - return 'Directory does not exist'; - } - const stats = await fs.stat(expandedPath); - if (!stats.isDirectory()) { - return 'Path must be a directory'; - } - } - return true; - }, - }, - ]); - - if (scanDirectory && scanDirectory.trim() !== '') { - console.log(chalk.dim('\nScanning for custom module sources...')); - - // Scan for all module.yaml files - const allModulePaths = await this.moduleManager.findModulesInProject(scanDirectory); - const { ModuleManager } = require('../modules/manager'); - const mm = new ModuleManager({ scanProjectForModules: true }); - - for (const untracked of untrackedCustomModules) { - let foundSource = null; - - // Try to find by module ID - for (const modulePath of allModulePaths) { - try { - const moduleInfo = await mm.getModuleInfo(modulePath); - if (moduleInfo && moduleInfo.id === untracked.id) { - foundSource = { - path: modulePath, - info: moduleInfo, - }; - break; - } - } catch { - // Continue searching - } - } - - if (foundSource) { - console.log(chalk.green(` āœ“ Found source for ${untracked.id}: ${path.relative(projectRoot, foundSource.path)}`)); - - // Add to manifest - await this.manifest.addCustomModule(bmadDir, { - id: untracked.id, - name: foundSource.info.name || untracked.name, - sourcePath: path.resolve(foundSource.path), - installDate: new Date().toISOString(), - tracked: true, - }); - - // Add to customModuleSources for processing - customModuleSources.set(untracked.id, { - id: untracked.id, - name: foundSource.info.name || untracked.name, - sourcePath: path.resolve(foundSource.path), - }); - } else { - console.log(chalk.yellow(` ⚠ Could not find source for ${untracked.id}`)); - } - } - } - } - - console.log(chalk.dim('\nUntracked custom modules will remain installed but cannot be updated without their source.')); - spinner.start('Preparing update...'); - } - // Handle missing custom module sources using shared method const customModuleResult = await this.handleMissingCustomSources( customModuleSources, @@ -2414,18 +2325,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: hasUpdate: true, })); - // Add untracked modules to the update list but mark them as untrackable - for (const untracked of untrackedCustomModules) { - if (!customModuleSources.has(untracked.id)) { - customModulesFromManifest.push({ - ...untracked, - isCustom: true, - hasUpdate: false, // Can't update without source - untracked: true, - }); - } - } - const allAvailableModules = [...availableModules, ...customModulesFromManifest]; const availableModuleIds = new Set(allAvailableModules.map((m) => m.id)); diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js index 2d0c4407..20272735 100644 --- a/tools/cli/installers/lib/modules/manager.js +++ b/tools/cli/installers/lib/modules/manager.js @@ -28,7 +28,6 @@ class ModuleManager { this.modulesSourcePath = getSourcePath('modules'); this.xmlHandler = new XmlHandler(); this.bmadFolderName = 'bmad'; // Default, can be overridden - this.scanProjectForModules = options.scanProjectForModules !== false; // Default to true for backward compatibility this.customModulePaths = new Map(); // Initialize custom module paths } @@ -116,76 +115,6 @@ class ModuleManager { } } - /** - * Find all modules in the project by searching for module.yaml files - * @returns {Array} List of module paths - */ - async findModulesInProject() { - const projectRoot = getProjectRoot(); - const modulePaths = new Set(); - - // Helper function to recursively scan directories - async function scanDirectory(dir, excludePaths = []) { - try { - const entries = await fs.readdir(dir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - - // Skip hidden directories, node_modules, and literal placeholder directories - if ( - entry.name.startsWith('.') || - entry.name === 'node_modules' || - entry.name === 'dist' || - entry.name === 'build' || - entry.name === '{project-root}' - ) { - continue; - } - - // Skip excluded paths - if (excludePaths.some((exclude) => fullPath.startsWith(exclude))) { - continue; - } - - if (entry.isDirectory()) { - // Skip core module - it's always installed first and not selectable - if (entry.name === 'core') { - continue; - } - - // Check if this directory contains a module (module.yaml OR custom.yaml) - const moduleConfigPath = path.join(fullPath, 'module.yaml'); - const installerConfigPath = path.join(fullPath, '_module-installer', 'module.yaml'); - const customConfigPath = path.join(fullPath, '_module-installer', 'custom.yaml'); - const rootCustomConfigPath = path.join(fullPath, 'custom.yaml'); - - if ( - (await fs.pathExists(moduleConfigPath)) || - (await fs.pathExists(installerConfigPath)) || - (await fs.pathExists(customConfigPath)) || - (await fs.pathExists(rootCustomConfigPath)) - ) { - modulePaths.add(fullPath); - // Don't scan inside modules - they might have their own nested structures - continue; - } - - // Recursively scan subdirectories - await scanDirectory(fullPath, excludePaths); - } - } - } catch { - // Ignore errors (e.g., permission denied) - } - } - - // Scan the entire project, but exclude src/modules since we handle it separately - await scanDirectory(projectRoot, [this.modulesSourcePath]); - - return [...modulePaths]; - } - /** * List all available modules (excluding core which is always installed) * @returns {Object} Object with modules array and customModules array @@ -228,43 +157,19 @@ class ModuleManager { } } - // Then, find all other modules in the project (only if scanning is enabled) - if (this.scanProjectForModules) { - const otherModulePaths = await this.findModulesInProject(); - for (const modulePath of otherModulePaths) { - const moduleName = path.basename(modulePath); - const relativePath = path.relative(getProjectRoot(), modulePath); - - // Skip core module - it's always installed first and not selectable - if (moduleName === 'core') { - continue; - } - - const moduleInfo = await this.getModuleInfo(modulePath, moduleName, relativePath); - if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) { - // Avoid duplicates - skip if we already have this module ID - if (moduleInfo.isCustom) { - customModules.push(moduleInfo); - } else { - modules.push(moduleInfo); - } - } - } - - // Also check for cached custom modules in _config/custom/ - if (this.bmadDir) { - const customCacheDir = path.join(this.bmadDir, '_config', 'custom'); - if (await fs.pathExists(customCacheDir)) { - const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true }); - for (const entry of cacheEntries) { - if (entry.isDirectory()) { - const cachePath = path.join(customCacheDir, entry.name); - const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_config/custom'); - if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) { - moduleInfo.isCustom = true; - moduleInfo.fromCache = true; - customModules.push(moduleInfo); - } + // Check for cached custom modules in _config/custom/ + if (this.bmadDir) { + const customCacheDir = path.join(this.bmadDir, '_config', 'custom'); + if (await fs.pathExists(customCacheDir)) { + const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true }); + for (const entry of cacheEntries) { + if (entry.isDirectory()) { + const cachePath = path.join(customCacheDir, entry.name); + const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_config/custom'); + if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) { + moduleInfo.isCustom = true; + moduleInfo.fromCache = true; + customModules.push(moduleInfo); } } } diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index 4b7f1ae3..9f931638 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -307,6 +307,14 @@ class UI { selectedModules = [...installedModuleIds]; } + // After module selection, ask about custom modules + const customModuleResult = await this.handleCustomModulesInModifyFlow(confirmedDirectory, selectedModules); + + // Merge any selected custom modules + if (customModuleResult.selectedCustomModules.length > 0) { + selectedModules.push(...customModuleResult.selectedCustomModules); + } + // Get tool selection const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules); @@ -337,7 +345,7 @@ class UI { ides: toolSelection.ides, skipIde: toolSelection.skipIde, coreConfig: coreConfig, - customContent: { hasCustomContent: false }, + customContent: customModuleResult.customContentConfig, enableAgentVibes: enableTts, agentVibesInstalled: false, }; @@ -734,14 +742,8 @@ class UI { // Add official modules const { ModuleManager } = require('../installers/lib/modules/manager'); - // For new installations, don't scan project yet (will do after custom content is discovered) - // For existing installations, scan if user selected custom content - const shouldScanProject = - !isNewInstallation && customContentConfig && customContentConfig.hasCustomContent && customContentConfig.selected; - const moduleManager = new ModuleManager({ - scanProjectForModules: shouldScanProject, - }); - const { modules: availableModules, customModules: customModulesFromProject } = await moduleManager.listAvailable(); + const moduleManager = new ModuleManager(); + const { modules: availableModules, customModules: customModulesFromCache } = await moduleManager.listAvailable(); // First, add all items to appropriate sections const allCustomModules = []; @@ -749,14 +751,14 @@ class UI { // Add custom content items from directory allCustomModules.push(...customContentItems); - // Add custom modules from project scan (if scanning is enabled) - for (const mod of customModulesFromProject) { + // Add custom modules from cache + for (const mod of customModulesFromCache) { // Skip if this module is already in customContentItems (by path) const isDuplicate = allCustomModules.some((item) => item.path && mod.path && path.resolve(item.path) === path.resolve(mod.path)); if (!isDuplicate) { allCustomModules.push({ - name: `${chalk.cyan('āœ“')} ${mod.name} ${chalk.gray(`(${mod.source})`)}`, + name: `${chalk.cyan('āœ“')} ${mod.name} ${chalk.gray(`(cached)`)}`, value: mod.id, checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id), }); @@ -803,7 +805,9 @@ class UI { }, ]); - return moduleAnswer.modules || []; + const selected = moduleAnswer.modules || []; + + return selected; } /** @@ -1472,6 +1476,136 @@ class UI { return customContentConfig; } + + /** + * Handle custom modules in the modify flow + * @param {string} directory - Installation directory + * @param {Array} selectedModules - Currently selected modules + * @returns {Object} Result with selected custom modules and custom content config + */ + async handleCustomModulesInModifyFlow(directory, selectedModules) { + // Get existing installation to find custom modules + const { existingInstall } = await this.getExistingInstallation(directory); + + // Check if there are any custom modules in cache + const { Installer } = require('../installers/lib/core/installer'); + const installer = new Installer(); + const { bmadDir } = await installer.findBmadDir(directory); + + const cacheDir = path.join(bmadDir, '_config', 'custom'); + const cachedCustomModules = []; + + if (await fs.pathExists(cacheDir)) { + const entries = await fs.readdir(cacheDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const moduleYamlPath = path.join(cacheDir, entry.name, 'module.yaml'); + if (await fs.pathExists(moduleYamlPath)) { + const yaml = require('yaml'); + const content = await fs.readFile(moduleYamlPath, 'utf8'); + const moduleData = yaml.parse(content); + + cachedCustomModules.push({ + id: entry.name, + name: moduleData.name || entry.name, + description: moduleData.description || 'Custom module from cache', + checked: selectedModules.includes(entry.name), + fromCache: true, + }); + } + } + } + } + + const result = { + selectedCustomModules: [], + customContentConfig: { hasCustomContent: false }, + }; + + if (cachedCustomModules.length === 0) { + return result; + } + + // Ask user about custom modules + console.log(chalk.cyan('\nāš™ļø Custom Modules')); + console.log(chalk.dim('Found custom modules in your installation:')); + + const { customAction } = await inquirer.prompt([ + { + type: 'list', + name: 'customAction', + message: 'What would you like to do with custom modules?', + choices: [ + { name: 'Keep all existing custom modules', value: 'keep' }, + { name: 'Select which custom modules to keep', value: 'select' }, + { name: 'Add new custom modules', value: 'add' }, + { name: 'Remove all custom modules', value: 'remove' }, + ], + default: 'keep', + }, + ]); + + switch (customAction) { + case 'keep': { + // Keep all existing custom modules + result.selectedCustomModules = cachedCustomModules.map((m) => m.id); + console.log(chalk.dim(`Keeping ${result.selectedCustomModules.length} custom module(s)`)); + break; + } + + case 'select': { + // Let user choose which to keep + const choices = cachedCustomModules.map((m) => ({ + name: `${m.name} ${chalk.gray(`(${m.id})`)}`, + value: m.id, + })); + + const { keepModules } = await inquirer.prompt([ + { + type: 'checkbox', + name: 'keepModules', + message: 'Select custom modules to keep:', + choices: choices, + default: cachedCustomModules.filter((m) => m.checked).map((m) => m.id), + }, + ]); + result.selectedCustomModules = keepModules; + break; + } + + case 'add': { + // First ask to keep existing ones + const { keepExisting } = await inquirer.prompt([ + { + type: 'confirm', + name: 'keepExisting', + message: 'Keep existing custom modules?', + default: true, + }, + ]); + + if (keepExisting) { + result.selectedCustomModules = cachedCustomModules.map((m) => m.id); + } + + // Then prompt for new ones (reuse existing method) + const newCustomContent = await this.promptCustomContentSource(); + if (newCustomContent.hasCustomContent && newCustomContent.selected) { + result.selectedCustomModules.push(...newCustomContent.selectedModuleIds); + result.customContentConfig = newCustomContent; + } + break; + } + + case 'remove': { + // Remove all custom modules + console.log(chalk.yellow('All custom modules will be removed from the installation')); + break; + } + } + + return result; + } } module.exports = { UI };