diff --git a/777775/_bmad-output/bmb-creations/custom.yaml b/777775/_bmad-output/bmb-creations/custom.yaml deleted file mode 100644 index 17c94389..00000000 --- a/777775/_bmad-output/bmb-creations/custom.yaml +++ /dev/null @@ -1,3 +0,0 @@ -code: my-custom-bmad -name: "Brianmadison-Custom-BMad: Sample Stand Alone Custom Agents and Workflows" -default_selected: true diff --git a/src/modules/bmb/_module-installer/installer.js b/src/modules/bmb/_module-installer/installer.js deleted file mode 100644 index 9bf68577..00000000 --- a/src/modules/bmb/_module-installer/installer.js +++ /dev/null @@ -1,76 +0,0 @@ -const fs = require('fs-extra'); -const path = require('node:path'); -const chalk = require('chalk'); - -/** - * BMB Module Installer - * Sets up custom agent and workflow locations for the BMad Builder module - * - * @param {Object} options - Installation options - * @param {string} options.projectRoot - The root directory of the target project - * @param {Object} options.config - Module configuration from module.yaml - * @param {Object} options.coreConfig - Core configuration containing user_name - * @param {Array} options.installedIDEs - Array of IDE codes that were installed - * @param {Object} options.logger - Logger instance for output - * @returns {Promise} - Success status - */ -async function install(options) { - const { projectRoot, config, coreConfig, installedIDEs, logger } = options; - - try { - logger.log(chalk.blue('🔧 Setting up BMB Module...')); - - // Generate custom.yaml in bmb_creations_output_folder - if (config['bmb_creations_output_folder']) { - // The config value contains {project-root} which needs to be resolved - const rawLocation = config['bmb_creations_output_folder']; - const customLocation = rawLocation.replace('{project-root}', projectRoot); - const customDestPath = path.join(customLocation, 'custom.yaml'); - - logger.log(chalk.cyan(` Setting up custom agents at: ${customLocation}`)); - - // Ensure the directory exists - await fs.ensureDir(customLocation); - - // Generate the custom.yaml content - const userName = (coreConfig && coreConfig.user_name) || 'my'; - const customContent = `code: my-custom-bmad -name: "${userName}-Custom-BMad: Sample Stand Alone Custom Agents and Workflows" -default_selected: true -`; - - // Write the custom.yaml file (only if it doesn't exist to preserve user changes) - if (await fs.pathExists(customDestPath)) { - logger.log(chalk.yellow(` ✓ custom.yaml already exists at ${customDestPath}`)); - } else { - await fs.writeFile(customDestPath, customContent, 'utf8'); - logger.log(chalk.green(` ✓ Created custom.yaml at ${customDestPath}`)); - } - } - - // Set up custom module location if configured - if (config['bmb_creations_output_folder']) { - const rawModuleLocation = config['bmb_creations_output_folder']; - const moduleLocation = rawModuleLocation.replace('{project-root}', projectRoot); - - logger.log(chalk.cyan(` Setting up custom modules at: ${moduleLocation}`)); - - // Ensure the directory exists - await fs.ensureDir(moduleLocation); - logger.log(chalk.green(` ✓ Created modules directory at ${moduleLocation}`)); - } - - // Handle IDE-specific configurations if needed - if (installedIDEs && installedIDEs.length > 0) { - logger.log(chalk.cyan(` Configuring BMB for IDEs: ${installedIDEs.join(', ')}`)); - } - - logger.log(chalk.green('✓ BMB Module setup complete')); - return true; - } catch (error) { - logger.error(chalk.red(`Error setting up BMB module: ${error.message}`)); - return false; - } -} - -module.exports = { install }; diff --git a/src/modules/cis/module.yaml b/src/modules/cis/module.yaml index 48ac552a..c1f72551 100644 --- a/src/modules/cis/module.yaml +++ b/src/modules/cis/module.yaml @@ -1,7 +1,7 @@ code: cis name: "CIS: Creative Innovation Suite" header: "Creative Innovation Suite (CIS) Module" -subheader: "No Configuration needed - uses Core Config only." +subheader: "No custom configuration required - uses Core settings only" default_selected: false # This module will not be selected by default for new installations # Variables from Core Config inserted: @@ -10,7 +10,3 @@ default_selected: false # This module will not be selected by default for new in ## document_output_language ## output_folder ## bmad_memory - -creativity_self_assessment: - prompt: "On a scale of 1 to 10, how would you rate your current level of creativity?" - result: "{value}" diff --git a/tools/cli/commands/install.js b/tools/cli/commands/install.js index 3e027b2a..86d6bef3 100644 --- a/tools/cli/commands/install.js +++ b/tools/cli/commands/install.js @@ -55,14 +55,11 @@ module.exports = { // Check if installation succeeded if (result && result.success) { - console.log(chalk.green('\n✨ Installation complete!')); - console.log(chalk.cyan('BMAD Core and Selected Modules have been installed to:'), chalk.bold(result.path)); - console.log(chalk.yellow('\nThank you for helping test the early release version of the new BMad Core and BMad Method!')); - console.log(chalk.cyan('Stable Beta coming soon - please read the full README.md and linked documentation to get started!')); - // Run AgentVibes installer if needed if (result.needsAgentVibes) { - console.log(chalk.magenta('\n🎙️ AgentVibes TTS Setup')); + // Add some spacing before AgentVibes setup + console.log(''); + console.log(chalk.magenta('🎙️ AgentVibes TTS Setup')); console.log(chalk.cyan('AgentVibes provides voice synthesis for BMAD agents with:')); console.log(chalk.dim(' • ElevenLabs AI (150+ premium voices)')); console.log(chalk.dim(' • Piper TTS (50+ free voices)\n')); @@ -91,6 +88,7 @@ module.exports = { shell: true, }); console.log(chalk.green('\n✓ AgentVibes installation complete')); + console.log(chalk.cyan('\n✨ BMAD with TTS is ready to use!')); } catch { console.log(chalk.yellow('\n⚠ AgentVibes installation was interrupted or failed')); console.log(chalk.cyan('You can run it manually later with:')); diff --git a/tools/cli/installers/lib/core/config-collector.js b/tools/cli/installers/lib/core/config-collector.js index f1f633b1..d31af833 100644 --- a/tools/cli/installers/lib/core/config-collector.js +++ b/tools/cli/installers/lib/core/config-collector.js @@ -254,6 +254,26 @@ class ConfigCollector { const configKeys = Object.keys(moduleConfig).filter((key) => key !== 'prompt'); const existingKeys = this.existingConfig && this.existingConfig[moduleName] ? Object.keys(this.existingConfig[moduleName]) : []; + // Check if this module has no configuration keys at all (like CIS) + // Filter out metadata fields and only count actual config objects + const metadataFields = new Set(['code', 'name', 'header', 'subheader', 'default_selected']); + const actualConfigKeys = configKeys.filter((key) => !metadataFields.has(key)); + const hasNoConfig = actualConfigKeys.length === 0; + + // If module has no config keys at all, handle it specially + if (hasNoConfig && moduleConfig.subheader) { + // Add blank line for better readability (matches other modules) + console.log(); + const moduleDisplayName = moduleConfig.header || `${moduleName.toUpperCase()} Module`; + + // Display the module name in color first (matches other modules) + console.log(chalk.cyan('?') + ' ' + chalk.magenta(moduleDisplayName)); + + // Show the subheader since there's no configuration to ask about + console.log(chalk.dim(` ✓ ${moduleConfig.subheader}`)); + return false; // No new fields + } + // Find new interactive fields (with prompt) const newKeys = configKeys.filter((key) => { const item = moduleConfig[key]; @@ -302,11 +322,12 @@ class ConfigCollector { this.allAnswers[`${moduleName}_user_name`] = this.getDefaultUsername(); } } - // Show "no config" message for modules with no new questions - console.log(chalk.dim(` ✓ ${moduleName.toUpperCase()} module already up to date`)); - return false; // No new fields } + // Show "no config" message for modules with no new questions (that have config keys) + console.log(chalk.dim(` ✓ ${moduleName.toUpperCase()} module already up to date`)); + return false; // No new fields + // If we have new fields (interactive or static), process them if (newKeys.length > 0 || newStaticKeys.length > 0) { const questions = []; @@ -710,8 +731,43 @@ class ConfigCollector { // No longer display completion boxes - keep output clean } else { - // No questions for this module - show completion message - console.log(chalk.dim(` ✓ ${moduleName.toUpperCase()} module configured`)); + // No questions for this module - show completion message with header if available + const moduleDisplayName = moduleConfig.header || `${moduleName.toUpperCase()} Module`; + + // Check if this module has NO configuration keys at all (like CIS) + // Filter out metadata fields and only count actual config objects + const metadataFields = new Set(['code', 'name', 'header', 'subheader', 'default_selected']); + const actualConfigKeys = configKeys.filter((key) => !metadataFields.has(key)); + const hasNoConfig = actualConfigKeys.length === 0; + + if (hasNoConfig && (moduleConfig.subheader || moduleConfig.header)) { + // Module explicitly has no configuration - show with special styling + // Add blank line for better readability (matches other modules) + console.log(); + + // Display the module name in color first (matches other modules) + console.log(chalk.cyan('?') + ' ' + chalk.magenta(moduleDisplayName)); + + // Ask user if they want to accept defaults or customize on the next line + const { customize } = await inquirer.prompt([ + { + type: 'confirm', + name: 'customize', + message: 'Accept Defaults (no to customize)?', + default: true, + }, + ]); + + // Show the subheader if available, otherwise show a default message + if (moduleConfig.subheader) { + console.log(chalk.dim(` ✓ ${moduleConfig.subheader}`)); + } else { + console.log(chalk.dim(` ✓ No custom configuration required`)); + } + } else { + // Module has config but just no questions to ask + console.log(chalk.dim(` ✓ ${moduleName.toUpperCase()} module configured`)); + } } // If we have no collected config for this module, but we have a module schema, diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 39ca0431..033a8260 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -1248,9 +1248,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: console.log = originalLog; if (spinner.isSpinning) { - spinner.succeed(`Configured ${validIdes.length} IDE${validIdes.length > 1 ? 's' : ''}`); + spinner.succeed(`Configured: ${validIdes.join(', ')}`); } else { - console.log(chalk.green(`✓ Configured ${validIdes.length} IDE${validIdes.length > 1 ? 's' : ''}`)); + console.log(chalk.green(`✓ Configured: ${validIdes.join(', ')}`)); } } @@ -1266,6 +1266,14 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: // Run module-specific installers after IDE setup spinner.start('Running module-specific installers...'); + // Create a conditional logger based on verbose mode + const verboseMode = process.env.BMAD_VERBOSE_INSTALL === 'true' || config.verbose; + const moduleLogger = { + log: (msg) => (verboseMode ? console.log(msg) : {}), // Only log in verbose mode + error: (msg) => console.error(msg), // Always show errors + warn: (msg) => console.warn(msg), // Always show warnings + }; + // Run core module installer if core was installed if (config.installCore || resolution.byModule.core) { spinner.text = 'Running core module installer...'; @@ -1274,11 +1282,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: installedIDEs: config.ides || [], moduleConfig: moduleConfigs.core || {}, coreConfig: moduleConfigs.core || {}, - logger: { - log: (msg) => console.log(msg), - error: (msg) => console.error(msg), - warn: (msg) => console.warn(msg), - }, + logger: moduleLogger, }); } @@ -1292,11 +1296,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: installedIDEs: config.ides || [], moduleConfig: moduleConfigs[moduleName] || {}, coreConfig: moduleConfigs.core || {}, - logger: { - log: (msg) => console.log(msg), - error: (msg) => console.error(msg), - warn: (msg) => console.warn(msg), - }, + logger: moduleLogger, }); } } @@ -1942,7 +1942,10 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: const genericTemplatePath = getSourcePath('utility', 'agent-components', 'agent.customize.template.yaml'); if (await fs.pathExists(genericTemplatePath)) { await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath, this.bmadFolderName || 'bmad'); - console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`)); + // Only show customize creation in verbose mode + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`)); + } } } } diff --git a/tools/cli/installers/lib/custom/handler.js b/tools/cli/installers/lib/custom/handler.js index 115c4a4c..c8aa52ee 100644 --- a/tools/cli/installers/lib/custom/handler.js +++ b/tools/cli/installers/lib/custom/handler.js @@ -320,7 +320,10 @@ class CustomHandler { if (await fs.pathExists(genericTemplatePath)) { let templateContent = await fs.readFile(genericTemplatePath, 'utf8'); await fs.writeFile(customizePath, templateContent, 'utf8'); - console.log(chalk.dim(` Created customize: custom-${agentName}.customize.yaml`)); + // Only show customize creation in verbose mode + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + console.log(chalk.dim(` Created customize: custom-${agentName}.customize.yaml`)); + } } } @@ -341,11 +344,14 @@ class CustomHandler { fileTrackingCallback(targetMdPath); } - console.log( - chalk.dim( - ` Compiled agent: ${agentName} -> ${path.relative(targetAgentsPath, targetMdPath)}${hasSidecar ? ' (with sidecar)' : ''}`, - ), - ); + // Only show compilation details in verbose mode + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + console.log( + chalk.dim( + ` Compiled agent: ${agentName} -> ${path.relative(targetAgentsPath, targetMdPath)}${hasSidecar ? ' (with sidecar)' : ''}`, + ), + ); + } } catch (error) { console.warn(chalk.yellow(` Failed to compile agent ${agentName}:`, error.message)); results.errors.push(`Failed to compile agent ${agentName}: ${error.message}`); diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js index 12ac96b1..5adf7f86 100644 --- a/tools/cli/installers/lib/modules/manager.js +++ b/tools/cli/installers/lib/modules/manager.js @@ -837,7 +837,10 @@ class ModuleManager { const genericTemplatePath = getSourcePath('utility', 'agent-components', 'agent.customize.template.yaml'); if (await fs.pathExists(genericTemplatePath)) { await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath); - console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`)); + // Only show customize creation in verbose mode + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`)); + } // Store original hash for modification detection const crypto = require('node:crypto'); @@ -926,9 +929,14 @@ class ModuleManager { await fs.writeFile(targetMdPath, xml, 'utf8'); } - console.log( - chalk.dim(` Compiled agent: ${agentName} -> ${path.relative(targetPath, targetMdPath)}${hasSidecar ? ' (with sidecar)' : ''}`), - ); + // Only show compilation details in verbose mode + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + console.log( + chalk.dim( + ` Compiled agent: ${agentName} -> ${path.relative(targetPath, targetMdPath)}${hasSidecar ? ' (with sidecar)' : ''}`, + ), + ); + } } catch (error) { console.warn(chalk.yellow(` Failed to compile agent ${agentName}:`, error.message)); } diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index d57c5dd8..97e2faca 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -18,8 +18,6 @@ class UI { */ async promptInstall() { CLIUtils.displayLogo(); - const version = CLIUtils.getVersion(); - CLIUtils.displaySection('BMAD™ Setup', `Build More, Architect Dreams v${version}`); const confirmedDirectory = await this.getConfirmedDirectory(); @@ -591,69 +589,26 @@ class UI { * @param {Object} result - Installation result */ showInstallSummary(result) { - CLIUtils.displaySection('Installation Complete', 'BMAD™ has been successfully installed'); - - const summary = [ - `📁 Installation Path: ${result.path}`, - `📦 Modules Installed: ${result.modules?.length > 0 ? result.modules.join(', ') : 'core only'}`, - `🔧 Tools Configured: ${result.ides?.length > 0 ? result.ides.join(', ') : 'none'}`, - ]; - - // Add AgentVibes TTS info if enabled - if (result.agentVibesEnabled) { - summary.push(`🎤 AgentVibes TTS: Enabled`); - } - - CLIUtils.displayBox(summary.join('\n\n'), { - borderColor: 'green', - borderStyle: 'round', - }); - - // Display TTS injection details if present - if (result.ttsInjectedFiles && result.ttsInjectedFiles.length > 0) { - console.log('\n' + chalk.cyan.bold('═══════════════════════════════════════════════════')); - console.log(chalk.cyan.bold(' AgentVibes TTS Injection Summary')); - console.log(chalk.cyan.bold('═══════════════════════════════════════════════════\n')); - - // Explain what TTS injection is - console.log(chalk.white.bold('What is TTS Injection?\n')); - console.log(chalk.dim(' TTS (Text-to-Speech) injection adds voice instructions to BMAD agents,')); - console.log(chalk.dim(' enabling them to speak their responses aloud using AgentVibes.\n')); - console.log(chalk.dim(' Example: When you activate the PM agent, it will greet you with')); - console.log(chalk.dim(' spoken audio like "Hey! I\'m your Project Manager. How can I help?"\n')); - - console.log(chalk.green(`✅ TTS injection applied to ${result.ttsInjectedFiles.length} file(s):\n`)); - - // Group by type - const partyModeFiles = result.ttsInjectedFiles.filter((f) => f.type === 'party-mode'); - const agentTTSFiles = result.ttsInjectedFiles.filter((f) => f.type === 'agent-tts'); - - if (partyModeFiles.length > 0) { - console.log(chalk.yellow(' Party Mode (multi-agent conversations):')); - for (const file of partyModeFiles) { - console.log(chalk.dim(` • ${file.path}`)); - } - } - - if (agentTTSFiles.length > 0) { - console.log(chalk.yellow(' Agent TTS (individual agent voices):')); - for (const file of agentTTSFiles) { - console.log(chalk.dim(` • ${file.path}`)); - } - } - - // Show backup info and restore command - console.log('\n' + chalk.white.bold('Backups & Recovery:\n')); - console.log(chalk.dim(' Pre-injection backups are stored in:')); - console.log(chalk.cyan(' ~/_bmad-tts-backups/\n')); - console.log(chalk.dim(' To restore original files (removes TTS instructions):')); - console.log(chalk.cyan(` bmad-tts-injector.sh --restore ${result.path}\n`)); - - console.log(chalk.cyan('💡 BMAD agents will now speak when activated!')); - console.log(chalk.dim(' Ensure AgentVibes is installed: https://agentvibes.org')); - } - + // Clean, simple completion message console.log('\n' + chalk.green.bold('✨ BMAD is ready to use!')); + + // Show installation summary in a simple format + console.log(chalk.dim(`Installed to: ${result.path}`)); + if (result.modules && result.modules.length > 0) { + console.log(chalk.dim(`Modules: ${result.modules.join(', ')}`)); + } + if (result.agentVibesEnabled) { + console.log(chalk.dim(`TTS: Enabled`)); + } + + // TTS injection info (simplified) + if (result.ttsInjectedFiles && result.ttsInjectedFiles.length > 0) { + console.log(chalk.dim(`\n💡 TTS enabled for ${result.ttsInjectedFiles.length} agent(s)`)); + console.log(chalk.dim(' Agents will now speak when using AgentVibes')); + } + + console.log(chalk.yellow('\nThank you for helping test the early release version of the new BMad Core and BMad Method!')); + console.log(chalk.cyan('Stable Beta coming soon - please read the full README.md and linked documentation to get started!')); } /**