Add Text-to-Speech Integration via TTS_INJECTION System (#934)
* feat: Add provider-agnostic TTS integration via injection point system
Implements comprehensive Text-to-Speech integration for BMAD agents using a generic
TTS_INJECTION marker system. When AgentVibes (or any compatible TTS provider) is
installed, all BMAD agents can speak their responses with unique AI voices.
## Key Features
**Provider-Agnostic Architecture**
- Uses generic `TTS_INJECTION` markers instead of vendor-specific naming
- Future-proof for multiple TTS providers beyond AgentVibes
- Clean separation - BMAD stays TTS-agnostic, providers handle injection
**Installation Flow**
- BMAD → AgentVibes: TTS instructions injected when AgentVibes detects existing BMAD installation
- AgentVibes → BMAD: TTS instructions injected during BMAD installation when AgentVibes detected
- User must manually create voice assignment file when AgentVibes installs first (documented limitation)
**Party Mode Voice Support**
- Each agent speaks with unique assigned voice in multi-agent discussions
- PM, Architect, Developer, Analyst, UX Designer, etc. - all with distinct voices
**Zero Breaking Changes**
- Fully backward compatible - works without any TTS provider
- `TTS_INJECTION` markers are benign HTML comments if not processed
- No changes to existing agent behavior or non-TTS workflows
## Implementation Details
**Files Modified:**
- `tools/cli/installers/lib/core/installer.js` - TTS injection processing logic
- `tools/cli/lib/ui.js` - AgentVibes detection and installation prompts
- `tools/cli/commands/install.js` - Post-install guidance for AgentVibes setup
- `src/utility/models/fragments/activation-rules.xml` - TTS_INJECTION marker for agents
- `src/core/workflows/party-mode/instructions.md` - TTS_INJECTION marker for party mode
**Injection Point System:**
```xml
<rules>
- ALWAYS communicate in {communication_language}
<!-- TTS_INJECTION:agent-tts -->
- Stay in character until exit selected
</rules>
```
When AgentVibes is detected, the installer replaces this marker with:
```
- When responding to user messages, speak your responses using TTS:
Call: `.claude/hooks/bmad-speak.sh '{agent-id}' '{response-text}'` after each response
IMPORTANT: Use single quotes - do NOT escape special characters like ! or $
```
**Special Character Handling:**
- Explicit guidance to use single quotes without escaping
- Prevents "backslash exclamation" artifacts in speech
**User Experience:**
```
User: "How should we architect this feature?"
Architect: [Text response] + 🔊 [Professional voice explains architecture]
```
Party Mode:
```
PM (John): "I'll focus on user value..." 🔊 [Male professional voice]
UX Designer (Sara): "From a user perspective..." 🔊 [Female voice]
Architect (Marcus): "The technical approach..." 🔊 [Male technical voice]
```
## Testing
**Unit Tests:** ✅ 62/62 passing
- 49/49 schema validation tests
- 13/13 installation component tests
**Integration Testing:**
- ✅ BMAD → AgentVibes (automatic injection)
- ✅ AgentVibes → BMAD (automatic injection)
- ✅ No TTS provider (markers remain as comments)
## Documentation
Comprehensive testing guide created with:
- Both installation scenario walkthroughs
- Verification commands and expected outputs
- Troubleshooting guidance
## Known Limitations
**AgentVibes → BMAD Installation Order:**
When AgentVibes installs first, voice assignment file must be created manually:
```bash
mkdir -p .bmad/_cfg
cat > .bmad/_cfg/agent-voice-map.csv << 'EOF'
agent_id,voice_name
pm,en_US-ryan-high
architect,en_US-danny-low
dev,en_US-joe-medium
EOF
```
This limitation exists to prevent false legacy v4 detection warnings from BMAD installer.
**Recommended:** Install BMAD first, then AgentVibes for automatic voice assignment.
## Related Work
**Companion Implementation:**
- Repository: paulpreibisch/AgentVibes
- Commits: 6 commits implementing injection processing and voice routing
- Features: Retroactive injection, file path extraction, escape stripping
**GitHub Issues:**
- paulpreibisch/AgentVibes#36 - BMAD agent ID support
## Breaking Changes
None. Feature is opt-in and requires separate TTS provider installation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Enforce project hooks over global hooks in party mode
before, claude would sometimes favor global agent vibes hooks over project specific
* feat: Automate AgentVibes installer invocation after BMAD install
Instead of showing manual installation instructions, the installer now:
- Prompts "Press Enter to start AgentVibes installer..."
- Automatically runs npx agentvibes@latest install
- Handles errors gracefully with fallback instructions
This provides a seamless installation flow matching the test script's
interactive approach.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: Add automated testing script and guide for PR #934
Added comprehensive testing tools for AgentVibes party mode integration:
- test-bmad-pr.sh: Fully automated installation and verification script
- Interactive mode selection (official PR or custom fork)
- Automatic BMAD CLI setup and linking
- AgentVibes installation with guided prompts
- Built-in verification checks for voice maps and hooks
- Saved configuration for quick re-testing
- TESTING.md: Complete testing documentation
- Quick start with one-line npx command
- Manual installation alternative
- Troubleshooting guide
- Cleanup instructions
Testers can now run a single command to test the full AgentVibes integration
without needing to understand the complex setup process.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Add shell: true to npx execSync to prevent permission denied error
The execSync call for 'npx agentvibes@latest install' was failing with
'Permission denied' because the shell was trying to execute 'agentvibes@latest'
directly instead of passing it as an argument to npx.
Adding shell: true ensures the command runs in a proper shell context
where npx can correctly interpret the @latest version syntax.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Remove duplicate AgentVibes installation step from test script
The test script was calling AgentVibes installer twice:
1. BMAD installer now automatically runs AgentVibes (new feature)
2. Test script had a separate Step 6 that also ran AgentVibes
This caused the installer to run twice, with the second call failing
because it was already installed.
Changes:
- Removed redundant Step 6 (AgentVibes installation)
- Updated Step 5 to indicate it includes AgentVibes
- Updated step numbers from 7 to 6 throughout
- Added guidance that AgentVibes runs automatically
Now the flow is cleaner: BMAD installer handles everything!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Address bmadcode review - preserve variables and move TTS logic to injection
Fixes requested changes from PR review:
1. Preserve {bmad_folder} variable placeholder
- Changed: {project_root}/.bmad/core/tasks/workflow.xml
- To: {project_root}/{bmad_folder}/core/tasks/workflow.xml
- Allows users to choose custom BMAD folder names during installation
2. Move TTS-specific hook guidance to injection system
- Removed hardcoded hook enforcement from source files
- Added hook guidance to processTTSInjectionPoints() in installer.js
- Now only appears when AgentVibes is installed (via TTS_INJECTION)
3. Maintain TTS-agnostic source architecture
- Source files remain clean of TTS-specific instructions
- TTS details injected at install-time only when needed
- Preserves provider-agnostic design principle
Changes made:
- src/core/workflows/party-mode/instructions.md
- Reverted .bmad to {bmad_folder} variable
- Replaced hardcoded hook guidance with <!-- TTS_INJECTION:party-mode -->
- Removed <note> about play-tts.sh hook location
- tools/cli/installers/lib/core/installer.js
- Added hook enforcement to party-mode injection replacement
- Guidance now injected only when enableAgentVibes is true
Addresses review comments from bmadcode:
- "needs to remain the variable. it will get set in the file at the install destination."
- "items like this we will need to inject if user is using claude and TTS"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Change 'claude-code' to 'claude' in test script instructions
The correct command to start Claude is 'claude', not 'claude-code'.
Updated line 362-363 in test-bmad-pr.sh to show the correct command.
* fix: Remove npm link from test script to avoid global namespace pollution
- Removed 'npm link' command that was installing BMAD globally
- Changed 'bmad install' to direct node execution using local clone
- Updated success message to reflect no global installation
This keeps testing fully isolated and prevents conflicts with:
- Existing BMAD installations
- Future official BMAD installs
- Orphaned symlinks when test directory is deleted
The test script now runs completely self-contained without modifying
the user's global npm environment.
---------
Co-authored-by: Claude Code <claude@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Paul Preibisch <paul@paulpreibisch.com>
Co-authored-by: Brian <bmadcode@gmail.com>
This commit is contained in:
parent
11a1dbaefc
commit
5702195ef7
|
|
@ -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
|
||||
```
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
<critical>The workflow execution engine is governed by: {project_root}/{bmad_folder}/core/tasks/workflow.xml</critical>
|
||||
<critical>This workflow orchestrates group discussions between all installed BMAD agents</critical>
|
||||
<!-- TTS_INJECTION:party-mode -->
|
||||
|
||||
<workflow>
|
||||
|
||||
|
|
@ -94,17 +95,36 @@
|
|||
</substep>
|
||||
|
||||
<substep n="3d" goal="Format and Present Responses">
|
||||
<action>Present each agent's contribution clearly:</action>
|
||||
<action>For each agent response, output text THEN trigger their voice:</action>
|
||||
|
||||
<procedure>
|
||||
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
|
||||
</procedure>
|
||||
|
||||
<format>
|
||||
[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]
|
||||
</format>
|
||||
<example>
|
||||
🏗️ [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."]
|
||||
</example>
|
||||
|
||||
<action>Maintain spacing between agents for readability</action>
|
||||
<action>Preserve each agent's unique voice throughout</action>
|
||||
<action>Always include the agent's icon emoji from the manifest before their name</action>
|
||||
<action>Trigger TTS for each agent immediately after outputting their text</action>
|
||||
|
||||
</substep>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<rules>
|
||||
- ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style
|
||||
<!-- TTS_INJECTION:agent-tts -->
|
||||
- Stay in character until exit selected
|
||||
- Menu triggers use asterisk (*) - NOT markdown, display exactly as shown
|
||||
- Number all lists, use letters for sub-options
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<void>} 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_INJECTION:* --> → 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:
|
||||
* <!-- TTS_INJECTION:feature-name -->
|
||||
*
|
||||
* 2. Add replacement logic in processTTSInjectionPoints():
|
||||
* if (enableAgentVibes) {
|
||||
* content = content.replace(/<!-- TTS_INJECTION:feature-name -->/g, 'actual code');
|
||||
* } else {
|
||||
* content = content.replace(/<!-- TTS_INJECTION:feature-name -->\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: <!-- TTS_INJECTION:feature-name -->
|
||||
* - 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: <!-- TTS_INJECTION:party-mode -->
|
||||
* 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: <!-- TTS_INJECTION:agent-tts -->
|
||||
* 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(
|
||||
* /<!-- TTS_INJECTION:new-feature -->/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(
|
||||
'<!-- TTS_INJECTION:party-mode -->',
|
||||
`<critical>IMPORTANT: Always use PROJECT hooks (.claude/hooks/), NEVER global hooks (~/.claude/hooks/)</critical>
|
||||
|
||||
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(
|
||||
'<!-- TTS_INJECTION:agent-tts -->',
|
||||
`- 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 <agent id="..."> 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(/<!-- TTS_INJECTION:party-mode -->\n?/g, '');
|
||||
content = content.replaceAll(/<!-- TTS_INJECTION:agent-tts -->\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;
|
||||
|
|
|
|||
|
|
@ -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<Object>} 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<boolean>} 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 };
|
||||
|
|
|
|||
Loading…
Reference in New Issue