diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 00000000..37357302 --- /dev/null +++ b/TESTING.md @@ -0,0 +1,115 @@ +# Testing AgentVibes Party Mode (PR #934) + +This guide helps you test the AgentVibes integration that adds multi-agent party mode with unique voices for each BMAD agent. + +## Quick Start + +We've created an automated test script that handles everything for you: + +```bash +curl -fsSL https://raw.githubusercontent.com/paulpreibisch/BMAD-METHOD/feature/agentvibes-tts-integration/test-bmad-pr.sh -o test-bmad-pr.sh +chmod +x test-bmad-pr.sh +./test-bmad-pr.sh +``` + +## What the Script Does + +The automated script will: + +1. Clone the BMAD repository +2. Checkout the PR branch with party mode features +3. Install BMAD CLI tools locally +4. Create a test BMAD project +5. Install AgentVibes TTS system +6. Configure unique voices for each agent +7. Verify the installation + +## Prerequisites + +- Node.js and npm installed +- Git installed +- ~500MB free disk space +- 10-15 minutes for complete setup + +## Manual Testing (Alternative) + +If you prefer manual installation: + +### 1. Clone and Setup BMAD + +```bash +git clone https://github.com/paulpreibisch/BMAD-METHOD.git +cd BMAD-METHOD +git fetch origin pull/934/head:agentvibes-party-mode +git checkout agentvibes-party-mode +cd tools/cli +npm install +npm link +``` + +### 2. Create Test Project + +```bash +mkdir -p ~/bmad-test-project +cd ~/bmad-test-project +bmad install +``` + +When prompted: + +- Enable TTS for agents? → **Yes** +- The installer will automatically prompt you to install AgentVibes + +### 3. Test Party Mode + +```bash +cd ~/bmad-test-project +claude-code +``` + +In Claude Code, run: + +``` +/bmad:core:workflows:party-mode +``` + +Each BMAD agent should speak with a unique voice! + +## Verification + +After installation, verify: + +✅ Voice map file exists: `.bmad/_cfg/agent-voice-map.csv` +✅ BMAD TTS hooks exist: `.claude/hooks/bmad-speak.sh` +✅ Each agent has a unique voice assigned +✅ Party mode works with distinct voices + +## Troubleshooting + +**No audio?** + +- Check: `.claude/hooks/play-tts.sh` exists +- Test current voice: `/agent-vibes:whoami` + +**Same voice for all agents?** + +- Check: `.bmad/_cfg/agent-voice-map.csv` has different voices +- List available voices: `/agent-vibes:list` + +## Report Issues + +Found a bug? Report it on the PR: +https://github.com/bmad-code-org/BMAD-METHOD/pull/934 + +## Cleanup + +To remove the test installation: + +```bash +# Remove test directory +rm -rf ~/bmad-test-project # or your custom test directory + +# Unlink BMAD CLI (optional) +cd ~/BMAD-METHOD/tools/cli +npm unlink +``` diff --git a/src/core/workflows/party-mode/instructions.md b/src/core/workflows/party-mode/instructions.md index 3ca8e052..6afd5ede 100644 --- a/src/core/workflows/party-mode/instructions.md +++ b/src/core/workflows/party-mode/instructions.md @@ -2,6 +2,7 @@ The workflow execution engine is governed by: {project_root}/{bmad_folder}/core/tasks/workflow.xml This workflow orchestrates group discussions between all installed BMAD agents + @@ -94,17 +95,36 @@ - Present each agent's contribution clearly: + For each agent response, output text THEN trigger their voice: + + + 1. Output the agent's text in format: [Icon Emoji] [Agent Name]: [dialogue] + 2. If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: + - Use Bash tool: `.claude/hooks/bmad-speak.sh "[Agent Name]" "[dialogue]"` + - This speaks the dialogue with the agent's unique voice + - Run in background (&) to not block next agent + 3. Repeat for each agent in the response + + - [Agent Name]: [Their response in their voice/style] + [Icon Emoji] [Agent Name]: [Their response in their voice/style] - [Another Agent]: [Their response, potentially referencing the first] + [Icon Emoji] [Another Agent]: [Their response, potentially referencing the first] - [Third Agent if selected]: [Their contribution] + [Icon Emoji] [Third Agent if selected]: [Their contribution] + + 🏗️ [Winston]: I recommend using microservices for better scalability. + [Bash: .claude/hooks/bmad-speak.sh "Winston" "I recommend using microservices for better scalability."] + + 📋 [John]: But a monolith would get us to market faster for MVP. + [Bash: .claude/hooks/bmad-speak.sh "John" "But a monolith would get us to market faster for MVP."] + Maintain spacing between agents for readability Preserve each agent's unique voice throughout + Always include the agent's icon emoji from the manifest before their name + Trigger TTS for each agent immediately after outputting their text diff --git a/src/utility/models/fragments/activation-rules.xml b/src/utility/models/fragments/activation-rules.xml index 8fdd9852..4835e834 100644 --- a/src/utility/models/fragments/activation-rules.xml +++ b/src/utility/models/fragments/activation-rules.xml @@ -1,5 +1,6 @@ - ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style + - Stay in character until exit selected - Menu triggers use asterisk (*) - NOT markdown, display exactly as shown - Number all lists, use letters for sub-options diff --git a/test-bmad-pr.sh b/test-bmad-pr.sh new file mode 100755 index 00000000..54cde458 --- /dev/null +++ b/test-bmad-pr.sh @@ -0,0 +1,381 @@ +#!/usr/bin/env bash +# +# BMAD PR Testing Script +# Interactive script to test BMAD PR #934 with AgentVibes integration +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="$SCRIPT_DIR/.test-bmad-config" + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +clear + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🎙️ BMAD AgentVibes Party Mode Testing Script" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo -e "${BLUE}What this script does:${NC}" +echo "" +echo " This script automates the process of testing BMAD's AgentVibes" +echo " integration (PR #934), which adds multi-agent party mode with" +echo " unique voices for each BMAD agent." +echo "" +echo -e "${BLUE}The script will:${NC}" +echo "" +echo " 1. Clone the BMAD repository" +echo " 2. Checkout the PR branch with party mode features" +echo " 3. Install BMAD CLI tools locally" +echo " 4. Create a test BMAD project" +echo " 5. Run BMAD installer (automatically installs AgentVibes)" +echo " 6. Verify the installation" +echo "" +echo -e "${YELLOW}Prerequisites:${NC}" +echo " • Node.js and npm installed" +echo " • Git installed" +echo " • ~500MB free disk space" +echo " • 10-15 minutes for complete setup" +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +read -p "Ready to continue? [Y/n]: " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ -n $REPLY ]]; then + echo "❌ Setup cancelled" + exit 0 +fi + +clear + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🔧 Testing Mode Selection" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo "Choose how you want to test:" +echo "" +echo " 1) Test official BMAD PR #934 (recommended for most users)" +echo " • Uses: github.com/bmad-code-org/BMAD-METHOD" +echo " • Branch: PR #934 (agentvibes-party-mode)" +echo " • Best for: Testing the official PR before it's merged" +echo "" +echo " 2) Test your forked repository" +echo " • Uses: Your GitHub fork" +echo " • Branch: Your custom branch (you choose)" +echo " • Best for: Testing your own changes or modifications" +echo "" + +# Load saved config if it exists +SAVED_MODE="" +SAVED_FORK="" +SAVED_BRANCH="" +SAVED_TEST_DIR="" +if [[ -f "$CONFIG_FILE" ]]; then + source "$CONFIG_FILE" +fi + +if [[ -n "$SAVED_MODE" ]]; then + echo -e "${BLUE}Last used: Mode $SAVED_MODE${NC}" + [[ -n "$SAVED_FORK" ]] && echo " Fork: $SAVED_FORK" + [[ -n "$SAVED_BRANCH" ]] && echo " Branch: $SAVED_BRANCH" + echo "" +fi + +read -p "Select mode [1/2]: " MODE_CHOICE +echo "" + +# Validate mode choice +while [[ ! "$MODE_CHOICE" =~ ^[12]$ ]]; do + echo -e "${RED}Invalid choice. Please enter 1 or 2.${NC}" + read -p "Select mode [1/2]: " MODE_CHOICE + echo "" +done + +# Configure based on mode +if [[ "$MODE_CHOICE" == "1" ]]; then + # Official PR mode + REPO_URL="https://github.com/bmad-code-org/BMAD-METHOD.git" + BRANCH_NAME="agentvibes-party-mode" + FETCH_PR=true + + echo -e "${GREEN}✓ Using official BMAD repository${NC}" + echo " Repository: $REPO_URL" + echo " Will fetch: PR #934 into branch '$BRANCH_NAME'" + echo "" +else + # Fork mode + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🍴 Fork Configuration" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + + if [[ -n "$SAVED_FORK" ]]; then + read -p "GitHub fork URL [$SAVED_FORK]: " FORK_INPUT + REPO_URL="${FORK_INPUT:-$SAVED_FORK}" + else + echo "Enter your forked repository URL:" + echo "(e.g., https://github.com/yourusername/BMAD-METHOD.git)" + read -p "Fork URL: " REPO_URL + fi + echo "" + + if [[ -n "$SAVED_BRANCH" ]]; then + read -p "Branch name [$SAVED_BRANCH]: " BRANCH_INPUT + BRANCH_NAME="${BRANCH_INPUT:-$SAVED_BRANCH}" + else + echo "Enter the branch name to test:" + echo "(e.g., agentvibes-party-mode, main, feature-xyz)" + read -p "Branch: " BRANCH_NAME + fi + echo "" + + FETCH_PR=false + + echo -e "${GREEN}✓ Using your fork${NC}" + echo " Repository: $REPO_URL" + echo " Branch: $BRANCH_NAME" + echo "" +fi + +# Ask for test directory +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📁 Test Directory" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +if [[ -n "$SAVED_TEST_DIR" ]]; then + read -p "Test directory [$SAVED_TEST_DIR]: " TEST_DIR + TEST_DIR="${TEST_DIR:-$SAVED_TEST_DIR}" +else + DEFAULT_DIR="$HOME/bmad-pr-test-$(date +%Y%m%d-%H%M%S)" + echo "Where should we create the test environment?" + read -p "Test directory [$DEFAULT_DIR]: " TEST_DIR + TEST_DIR="${TEST_DIR:-$DEFAULT_DIR}" +fi + +# Expand ~ to actual home directory +TEST_DIR="${TEST_DIR/#\~/$HOME}" + +echo "" + +# Save configuration +echo "SAVED_MODE=\"$MODE_CHOICE\"" > "$CONFIG_FILE" +[[ "$MODE_CHOICE" == "2" ]] && echo "SAVED_FORK=\"$REPO_URL\"" >> "$CONFIG_FILE" +[[ "$MODE_CHOICE" == "2" ]] && echo "SAVED_BRANCH=\"$BRANCH_NAME\"" >> "$CONFIG_FILE" +echo "SAVED_TEST_DIR=\"$TEST_DIR\"" >> "$CONFIG_FILE" +echo -e "${GREEN}✓ Configuration saved${NC}" +echo "" + +# Confirm before starting +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📋 Summary" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo " Repository: $REPO_URL" +echo " Branch: $BRANCH_NAME" +echo " Test dir: $TEST_DIR" +echo "" +read -p "Proceed with setup? [Y/n]: " -n 1 -r +echo +echo "" +if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ -n $REPLY ]]; then + echo "❌ Setup cancelled" + exit 0 +fi + +# Clean up old test directory if it exists +if [[ -d "$TEST_DIR" ]]; then + echo "⚠️ Test directory already exists: $TEST_DIR" + read -p "Delete and recreate? [Y/n]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then + rm -rf "$TEST_DIR" + echo -e "${GREEN}✓ Deleted old test directory${NC}" + else + echo -e "${YELLOW}⚠ Using existing directory (may have stale data)${NC}" + fi + echo "" +fi + +clear + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🚀 Starting Installation" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Step 1: Clone repository +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📥 Step 1/6: Cloning repository" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +mkdir -p "$TEST_DIR" +cd "$TEST_DIR" +git clone "$REPO_URL" BMAD-METHOD +cd BMAD-METHOD +echo "" +echo -e "${GREEN}✓ Repository cloned${NC}" +echo "" + +# Step 2: Checkout branch (different logic for PR vs fork) +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🔀 Step 2/6: Checking out branch" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +if [[ "$FETCH_PR" == true ]]; then + # Fetch PR from upstream + echo "Fetching PR #934 from upstream..." + git remote add upstream https://github.com/bmad-code-org/BMAD-METHOD.git + git fetch upstream pull/934/head:$BRANCH_NAME + git checkout $BRANCH_NAME + echo "" + echo -e "${GREEN}✓ Checked out PR branch: $BRANCH_NAME${NC}" +else + # Just checkout the specified branch from fork + git checkout $BRANCH_NAME + echo "" + echo -e "${GREEN}✓ Checked out branch: $BRANCH_NAME${NC}" +fi +echo "" + +# Step 3: Install BMAD CLI +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📦 Step 3/6: Installing BMAD CLI" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +cd tools/cli +npm install +echo "" +echo -e "${GREEN}✓ BMAD CLI dependencies installed${NC}" +echo "" + +# Step 4: Create test project +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📁 Step 4/6: Creating test project" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +cd "$TEST_DIR" +mkdir -p bmad-project +cd bmad-project +echo -e "${GREEN}✓ Test project directory created${NC}" +echo " Location: $TEST_DIR/bmad-project" +echo "" + +# Step 5: Run BMAD installer (includes AgentVibes setup) +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "⚙️ Step 5/6: Running BMAD installer with AgentVibes" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo -e "${YELLOW}Important: When prompted during installation:${NC}" +echo -e " • Enable TTS for agents? → ${GREEN}Yes${NC}" +echo -e " • Assign unique voices for party mode? → ${GREEN}Yes${NC}" +echo "" +echo -e "${YELLOW}AgentVibes will start automatically after BMAD installation.${NC}" +echo -e "${YELLOW}Recommended TTS settings:${NC}" +echo -e " • Provider: ${GREEN}Piper${NC} (free, local TTS)" +echo -e " • Download voices: ${GREEN}Yes${NC}" +echo "" +read -p "Press Enter to start BMAD installer..." +node "$TEST_DIR/BMAD-METHOD/tools/cli/bin/bmad.js" install + +echo "" +echo -e "${GREEN}✓ BMAD and AgentVibes installation complete${NC}" +echo "" + +# Step 6: Verification +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "✅ Step 6/6: Verifying installation" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +VERIFICATION_PASSED=true + +# Check for voice map file +if [[ -f ".bmad/_cfg/agent-voice-map.csv" ]]; then + echo -e "${GREEN}✓ Voice map file created${NC}" + echo " Location: .bmad/_cfg/agent-voice-map.csv" + echo "" + echo " Voice assignments:" + cat .bmad/_cfg/agent-voice-map.csv | sed 's/^/ /' + echo "" +else + echo -e "${RED}✗ Voice map file NOT found${NC}" + echo " Expected: .bmad/_cfg/agent-voice-map.csv" + echo " ${YELLOW}Warning: Agents may not have unique voices!${NC}" + echo "" + VERIFICATION_PASSED=false +fi + +# Check for AgentVibes hooks +if [[ -f ".claude/hooks/bmad-speak.sh" ]]; then + echo -e "${GREEN}✓ BMAD TTS hooks installed${NC}" + echo " Location: .claude/hooks/bmad-speak.sh" +else + echo -e "${RED}✗ BMAD TTS hooks NOT found${NC}" + echo " Expected: .claude/hooks/bmad-speak.sh" + VERIFICATION_PASSED=false +fi +echo "" + +# Check for Piper installation +if command -v piper &> /dev/null; then + PIPER_VERSION=$(piper --version 2>&1 || echo "unknown") + echo -e "${GREEN}✓ Piper TTS installed${NC}" + echo " Version: $PIPER_VERSION" +elif [[ -f ".agentvibes/providers/piper/piper" ]]; then + echo -e "${GREEN}✓ Piper TTS installed (local)${NC}" + echo " Location: .agentvibes/providers/piper/piper" +else + echo -e "${YELLOW}⚠ Piper not detected${NC}" + echo " (May still work if using ElevenLabs)" +fi +echo "" + +# Final status +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +if [[ "$VERIFICATION_PASSED" == true ]]; then + echo -e "${GREEN}🎉 Setup Complete - All Checks Passed!${NC}" +else + echo -e "${YELLOW}⚠️ Setup Complete - With Warnings${NC}" + echo "" + echo "Some verification checks failed. The installation may still work," + echo "but you might experience issues with party mode voices." +fi +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo -e "${BLUE}Next Steps:${NC}" +echo "" +echo " 1. Navigate to test project:" +echo -e " ${GREEN}cd $TEST_DIR/bmad-project${NC}" +echo "" +echo " 2. Start Claude session:" +echo -e " ${GREEN}claude${NC}" +echo "" +echo " 3. Test party mode:" +echo -e " ${GREEN}/bmad:core:workflows:party-mode${NC}" +echo "" +echo " 4. Verify each agent speaks with a unique voice!" +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo -e "${BLUE}Troubleshooting:${NC}" +echo "" +echo " • No audio? Check: .claude/hooks/play-tts.sh exists" +echo " • Same voice for all agents? Check: .bmad/_cfg/agent-voice-map.csv" +echo " • Test current voice: /agent-vibes:whoami" +echo " • List available voices: /agent-vibes:list" +echo "" +echo -e "${BLUE}Report Issues:${NC}" +echo " https://github.com/bmad-code-org/BMAD-METHOD/pull/934" +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" diff --git a/tools/cli/commands/install.js b/tools/cli/commands/install.js index d2706ee6..a9d484d5 100644 --- a/tools/cli/commands/install.js +++ b/tools/cli/commands/install.js @@ -59,6 +59,46 @@ module.exports = { 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')); + 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')); + + const readline = require('node:readline'); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + await new Promise((resolve) => { + rl.question(chalk.green('Press Enter to start AgentVibes installer...'), () => { + rl.close(); + resolve(); + }); + }); + + console.log(''); + + // Run AgentVibes installer + const { execSync } = require('node:child_process'); + try { + execSync('npx agentvibes@latest install', { + cwd: result.projectDir, + stdio: 'inherit', + shell: true, + }); + console.log(chalk.green('\n✓ AgentVibes installation complete')); + } catch { + console.log(chalk.yellow('\n⚠ AgentVibes installation was interrupted or failed')); + console.log(chalk.cyan('You can run it manually later with:')); + console.log(chalk.green(` cd ${result.projectDir}`)); + console.log(chalk.green(' npx agentvibes install\n')); + } + } + process.exit(0); } } catch (error) { diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 7473a307..8539ebbe 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -1,3 +1,23 @@ +/** + * File: tools/cli/installers/lib/core/installer.js + * + * BMAD Method - Business Model Agile Development Method + * Repository: https://github.com/paulpreibisch/BMAD-METHOD + * + * Copyright (c) 2025 Paul Preibisch + * Licensed under the Apache License, Version 2.0 + * + * --- + * + * @fileoverview Core BMAD installation orchestrator with AgentVibes injection point support + * @context Manages complete BMAD installation flow including core agents, modules, IDE configs, and optional TTS integration + * @architecture Orchestrator pattern - coordinates Detector, ModuleManager, IdeManager, and file operations to build complete BMAD installation + * @dependencies fs-extra, ora, chalk, detector.js, module-manager.js, ide-manager.js, config.js + * @entrypoints Called by install.js command via installer.install(config) + * @patterns Injection point processing (AgentVibes), placeholder replacement ({bmad_folder}), module dependency resolution + * @related GitHub AgentVibes#34 (injection points), ui.js (user prompts), copyFileWithPlaceholderReplacement() + */ + const path = require('node:path'); const fs = require('fs-extra'); const chalk = require('chalk'); @@ -69,10 +89,41 @@ class Installer { } /** - * Copy a file and replace {bmad_folder} placeholder with actual folder name - * @param {string} sourcePath - Source file path - * @param {string} targetPath - Target file path - * @param {string} bmadFolderName - The bmad folder name to use for replacement + * @function copyFileWithPlaceholderReplacement + * @intent Copy files from BMAD source to installation directory with dynamic content transformation + * @why Enables installation-time customization: {bmad_folder} replacement + optional AgentVibes TTS injection + * @param {string} sourcePath - Absolute path to source file in BMAD repository + * @param {string} targetPath - Absolute path to destination file in user's project + * @param {string} bmadFolderName - User's chosen bmad folder name (default: 'bmad') + * @returns {Promise} Resolves when file copy and transformation complete + * @sideeffects Writes transformed file to targetPath, creates parent directories if needed + * @edgecases Binary files bypass transformation, falls back to raw copy if UTF-8 read fails + * @calledby installCore(), installModule(), IDE installers during file vendoring + * @calls processTTSInjectionPoints(), fs.readFile(), fs.writeFile(), fs.copy() + * + * AI NOTE: This is the core transformation pipeline for ALL BMAD installation file copies. + * It performs two transformations in sequence: + * 1. {bmad_folder} → user's custom folder name (e.g., ".bmad" or "bmad") + * 2. → TTS bash calls (if enabled) OR stripped (if disabled) + * + * The injection point processing enables loose coupling between BMAD and TTS providers: + * - BMAD source contains injection markers (not actual TTS code) + * - At install-time, markers are replaced OR removed based on user preference + * - Result: Clean installs for users without TTS, working TTS for users with it + * + * PATTERN: Adding New Injection Points + * ===================================== + * 1. Add HTML comment marker in BMAD source file: + * + * + * 2. Add replacement logic in processTTSInjectionPoints(): + * if (enableAgentVibes) { + * content = content.replace(//g, 'actual code'); + * } else { + * content = content.replace(/\n?/g, ''); + * } + * + * 3. Document marker in instructions.md (if applicable) */ async copyFileWithPlaceholderReplacement(sourcePath, targetPath, bmadFolderName) { // List of text file extensions that should have placeholder replacement @@ -90,6 +141,9 @@ class Installer { content = content.replaceAll('{bmad_folder}', bmadFolderName); } + // Process AgentVibes injection points + content = this.processTTSInjectionPoints(content); + // Write to target with replaced content await fs.ensureDir(path.dirname(targetPath)); await fs.writeFile(targetPath, content, 'utf8'); @@ -103,6 +157,106 @@ class Installer { } } + /** + * @function processTTSInjectionPoints + * @intent Transform TTS injection markers based on user's installation choice + * @why Enables optional TTS integration without tight coupling between BMAD and TTS providers + * @param {string} content - Raw file content containing potential injection markers + * @returns {string} Transformed content with markers replaced (if enabled) or stripped (if disabled) + * @sideeffects None - pure transformation function + * @edgecases Returns content unchanged if no markers present, safe to call on all files + * @calledby copyFileWithPlaceholderReplacement() during every file copy operation + * @calls String.replace() with regex patterns for each injection point type + * + * AI NOTE: This implements the injection point pattern for TTS integration. + * Key architectural decisions: + * + * 1. **Why Injection Points vs Direct Integration?** + * - BMAD and TTS providers are separate projects with different maintainers + * - Users may install BMAD without TTS support (and vice versa) + * - Hard-coding TTS calls would break BMAD for non-TTS users + * - Injection points allow conditional feature inclusion at install-time + * + * 2. **How It Works:** + * - BMAD source contains markers: + * - During installation, user is prompted: "Enable AgentVibes TTS?" + * - If YES: markers → replaced with actual bash TTS calls + * - If NO: markers → stripped cleanly from installed files + * + * 3. **State Management:** + * - this.enableAgentVibes set in install() method from config.enableAgentVibes + * - config.enableAgentVibes comes from ui.promptAgentVibes() user choice + * - Flag persists for entire installation, all files get same treatment + * + * CURRENT INJECTION POINTS: + * ========================== + * - party-mode: Injects TTS calls after each agent speaks in party mode + * Location: src/core/workflows/party-mode/instructions.md + * Marker: + * Replacement: Bash call to .claude/hooks/bmad-speak.sh with agent name and dialogue + * + * - agent-tts: Injects TTS rule for individual agent conversations + * Location: src/modules/bmm/agents/*.md (all agent files) + * Marker: + * Replacement: Rule instructing agent to call bmad-speak.sh with agent ID and response + * + * ADDING NEW INJECTION POINTS: + * ============================= + * 1. Add new case in this function: + * content = content.replace( + * //g, + * `code to inject when enabled` + * ); + * + * 2. Add marker to BMAD source file at injection location + * + * 3. Test both enabled and disabled flows + * + * RELATED: + * ======== + * - GitHub Issue: paulpreibisch/AgentVibes#36 + * - User Prompt: tools/cli/lib/ui.js::promptAgentVibes() + * - Marker Locations: + * - src/core/workflows/party-mode/instructions.md:101 + * - src/modules/bmm/agents/*.md (rules sections) + * - TTS Hook: .claude/hooks/bmad-speak.sh (in AgentVibes repo) + */ + processTTSInjectionPoints(content) { + // Check if AgentVibes is enabled (set during installation configuration) + const enableAgentVibes = this.enableAgentVibes || false; + + if (enableAgentVibes) { + // Replace party-mode injection marker with actual TTS call + // Use single quotes to prevent shell expansion of special chars like ! + content = content.replaceAll( + '', + `IMPORTANT: Always use PROJECT hooks (.claude/hooks/), NEVER global hooks (~/.claude/hooks/) + +If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: + - Use Bash tool: \`.claude/hooks/bmad-speak.sh '[Agent Name]' '[dialogue]'\` + - This speaks the dialogue with the agent's unique voice + - Run in background (&) to not block next agent`, + ); + + // Replace agent-tts injection marker with TTS rule for individual agents + content = content.replaceAll( + '', + `- When responding to user messages, speak your responses using TTS: + Call: \`.claude/hooks/bmad-speak.sh '{agent-id}' '{response-text}'\` after each response + Replace {agent-id} with YOUR agent ID from tag at top of this file + Replace {response-text} with the text you just output to the user + IMPORTANT: Use single quotes as shown - do NOT escape special characters like ! or $ inside single quotes + Run in background (&) to avoid blocking`, + ); + } else { + // Strip injection markers cleanly when AgentVibes is disabled + content = content.replaceAll(/\n?/g, ''); + content = content.replaceAll(/\n?/g, ''); + } + + return content; + } + /** * Collect Tool/IDE configurations after module configuration * @param {string} projectDir - Project directory @@ -271,6 +425,9 @@ class Installer { const bmadFolderName = moduleConfigs.core && moduleConfigs.core.bmad_folder ? moduleConfigs.core.bmad_folder : 'bmad'; this.bmadFolderName = bmadFolderName; // Store for use in other methods + // Store AgentVibes configuration for injection point processing + this.enableAgentVibes = config.enableAgentVibes || false; + // Set bmad folder name on module manager and IDE manager for placeholder replacement this.moduleManager.setBmadFolderName(bmadFolderName); this.ideManager.setBmadFolderName(bmadFolderName); @@ -861,7 +1018,14 @@ class Installer { customFiles: customFiles.length > 0 ? customFiles : undefined, }); - return { success: true, path: bmadDir, modules: config.modules, ides: config.ides }; + return { + success: true, + path: bmadDir, + modules: config.modules, + ides: config.ides, + needsAgentVibes: this.enableAgentVibes && !config.agentVibesInstalled, + projectDir: projectDir, + }; } catch (error) { spinner.fail('Installation failed'); throw error; diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index 8de8825e..730ce4f9 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -1,3 +1,23 @@ +/** + * File: tools/cli/lib/ui.js + * + * BMAD Method - Business Model Agile Development Method + * Repository: https://github.com/paulpreibisch/BMAD-METHOD + * + * Copyright (c) 2025 Paul Preibisch + * Licensed under the Apache License, Version 2.0 + * + * --- + * + * @fileoverview Interactive installation prompts and user input collection for BMAD CLI + * @context Guides users through installation configuration including core settings, modules, IDEs, and optional AgentVibes TTS + * @architecture Facade pattern - presents unified installation flow, delegates to Detector/ConfigCollector/IdeManager for specifics + * @dependencies inquirer (prompts), chalk (formatting), detector.js (existing installation detection) + * @entrypoints Called by install.js command via ui.promptInstall(), returns complete configuration object + * @patterns Progressive disclosure (prompts in order), early IDE selection (Windows compat), AgentVibes auto-detection + * @related installer.js (consumes config), AgentVibes#34 (TTS integration), promptAgentVibes() + */ + const chalk = require('chalk'); const inquirer = require('inquirer'); const path = require('node:path'); @@ -99,6 +119,9 @@ class UI { const moduleChoices = await this.getModuleChoices(installedModuleIds); const selectedModules = await this.selectModules(moduleChoices); + // Prompt for AgentVibes TTS integration + const agentVibesConfig = await this.promptAgentVibes(confirmedDirectory); + // Collect IDE tool selection AFTER configuration prompts (fixes Windows/PowerShell hang) // This allows text-based prompts to complete before the checkbox prompt const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules); @@ -114,6 +137,8 @@ class UI { ides: toolSelection.ides, skipIde: toolSelection.skipIde, coreConfig: coreConfig, // Pass collected core config to installer + enableAgentVibes: agentVibesConfig.enabled, // AgentVibes TTS integration + agentVibesInstalled: agentVibesConfig.alreadyInstalled, }; } @@ -639,6 +664,140 @@ class UI { // Resolve to the absolute path relative to the current working directory return path.resolve(expanded); } + + /** + * @function promptAgentVibes + * @intent Ask user if they want AgentVibes TTS integration during BMAD installation + * @why Enables optional voice features without forcing TTS on users who don't want it + * @param {string} projectDir - Absolute path to user's project directory + * @returns {Promise} Configuration object: { enabled: boolean, alreadyInstalled: boolean } + * @sideeffects None - pure user input collection, no files written + * @edgecases Shows warning if user enables TTS but AgentVibes not detected + * @calledby promptInstall() during installation flow, after core config, before IDE selection + * @calls checkAgentVibesInstalled(), inquirer.prompt(), chalk.green/yellow/dim() + * + * AI NOTE: This prompt is strategically positioned in installation flow: + * - AFTER core config (bmad_folder, user_name, etc) + * - BEFORE IDE selection (which can hang on Windows/PowerShell) + * + * Flow Logic: + * 1. Auto-detect if AgentVibes already installed (checks for hook files) + * 2. Show detection status to user (green checkmark or gray "not detected") + * 3. Prompt: "Enable AgentVibes TTS?" (defaults to true if detected) + * 4. If user says YES but AgentVibes NOT installed: + * → Show warning with installation link (graceful degradation) + * 5. Return config to promptInstall(), which passes to installer.install() + * + * State Flow: + * promptAgentVibes() → { enabled, alreadyInstalled } + * ↓ + * promptInstall() → config.enableAgentVibes + * ↓ + * installer.install() → this.enableAgentVibes + * ↓ + * processTTSInjectionPoints() → injects OR strips markers + * + * RELATED: + * ======== + * - Detection: checkAgentVibesInstalled() - looks for bmad-speak.sh and play-tts.sh + * - Processing: installer.js::processTTSInjectionPoints() + * - Markers: src/core/workflows/party-mode/instructions.md:101, src/modules/bmm/agents/*.md + * - GitHub Issue: paulpreibisch/AgentVibes#36 + */ + async promptAgentVibes(projectDir) { + CLIUtils.displaySection('🎤 Voice Features', 'Enable TTS for multi-agent conversations'); + + // Check if AgentVibes is already installed + const agentVibesInstalled = await this.checkAgentVibesInstalled(projectDir); + + if (agentVibesInstalled) { + console.log(chalk.green(' ✓ AgentVibes detected')); + } else { + console.log(chalk.dim(' AgentVibes not detected')); + } + + const answers = await inquirer.prompt([ + { + type: 'confirm', + name: 'enableTts', + message: 'Enable AgentVibes TTS? (Agents speak with unique voices in party mode)', + default: true, // Default to yes - recommended for best experience + }, + ]); + + if (answers.enableTts && !agentVibesInstalled) { + console.log(chalk.yellow('\n ⚠️ AgentVibes not installed')); + console.log(chalk.dim(' Install AgentVibes separately to enable TTS:')); + console.log(chalk.dim(' https://github.com/paulpreibisch/AgentVibes\n')); + } + + return { + enabled: answers.enableTts, + alreadyInstalled: agentVibesInstalled, + }; + } + + /** + * @function checkAgentVibesInstalled + * @intent Detect if AgentVibes TTS hooks are present in user's project + * @why Allows auto-enabling TTS and showing helpful installation guidance + * @param {string} projectDir - Absolute path to user's project directory + * @returns {Promise} true if both required AgentVibes hooks exist, false otherwise + * @sideeffects None - read-only file existence checks + * @edgecases Returns false if either hook missing (both required for functional TTS) + * @calledby promptAgentVibes() to determine default value and show detection status + * @calls fs.pathExists() twice (bmad-speak.sh, play-tts.sh) + * + * AI NOTE: This checks for the MINIMUM viable AgentVibes installation. + * + * Required Files: + * =============== + * 1. .claude/hooks/bmad-speak.sh + * - Maps agent display names → agent IDs → voice profiles + * - Calls play-tts.sh with agent's assigned voice + * - Created by AgentVibes installer + * + * 2. .claude/hooks/play-tts.sh + * - Core TTS router (ElevenLabs or Piper) + * - Provider-agnostic interface + * - Required by bmad-speak.sh + * + * Why Both Required: + * ================== + * - bmad-speak.sh alone: No TTS backend + * - play-tts.sh alone: No BMAD agent voice mapping + * - Both together: Full party mode TTS integration + * + * Detection Strategy: + * =================== + * We use simple file existence (not version checks) because: + * - Fast and reliable + * - Works across all AgentVibes versions + * - User will discover version issues when TTS runs (fail-fast) + * + * PATTERN: Adding New Detection Criteria + * ======================================= + * If future AgentVibes features require additional files: + * 1. Add new pathExists check to this function + * 2. Update documentation in promptAgentVibes() + * 3. Consider: should missing file prevent detection or just log warning? + * + * RELATED: + * ======== + * - AgentVibes Installer: creates these hooks + * - bmad-speak.sh: calls play-tts.sh with agent voices + * - Party Mode: uses bmad-speak.sh for agent dialogue + */ + async checkAgentVibesInstalled(projectDir) { + const fs = require('fs-extra'); + const path = require('node:path'); + + // Check for AgentVibes hook files + const hookPath = path.join(projectDir, '.claude', 'hooks', 'bmad-speak.sh'); + const playTtsPath = path.join(projectDir, '.claude', 'hooks', 'play-tts.sh'); + + return (await fs.pathExists(hookPath)) && (await fs.pathExists(playTtsPath)); + } } module.exports = { UI };