mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-01-30 04:32:02 +00:00
remove hard inclusion of AV from installer, to replace with module soon
This commit is contained in:
@@ -11,7 +11,6 @@ ignores:
|
|||||||
- .claude/**
|
- .claude/**
|
||||||
- .roo/**
|
- .roo/**
|
||||||
- .codex/**
|
- .codex/**
|
||||||
- .agentvibes/**
|
|
||||||
- .kiro/**
|
- .kiro/**
|
||||||
- sample-project/**
|
- sample-project/**
|
||||||
- test-project-install/**
|
- test-project-install/**
|
||||||
|
|||||||
@@ -20,10 +20,13 @@ This flexibility enables:
|
|||||||
|
|
||||||
## Categories
|
## Categories
|
||||||
|
|
||||||
|
- [Categories](#categories)
|
||||||
- [Custom Stand-Alone Modules](#custom-stand-alone-modules)
|
- [Custom Stand-Alone Modules](#custom-stand-alone-modules)
|
||||||
- [Custom Add-On Modules](#custom-add-on-modules)
|
- [Custom Add-On Modules](#custom-add-on-modules)
|
||||||
- [Custom Global Modules](#custom-global-modules)
|
- [Custom Global Modules](#custom-global-modules)
|
||||||
- [Custom Agents](#custom-agents)
|
- [Custom Agents](#custom-agents)
|
||||||
|
- [BMad Tiny Agents](#bmad-tiny-agents)
|
||||||
|
- [Simple and Expert Agents](#simple-and-expert-agents)
|
||||||
- [Custom Workflows](#custom-workflows)
|
- [Custom Workflows](#custom-workflows)
|
||||||
|
|
||||||
## Custom Stand-Alone Modules
|
## Custom Stand-Alone Modules
|
||||||
@@ -59,7 +62,6 @@ Similar to Custom Stand-Alone Modules, but designed to add functionality that ap
|
|||||||
|
|
||||||
Examples include:
|
Examples include:
|
||||||
|
|
||||||
- The current TTS (Text-to-Speech) functionality for Claude, which will soon be converted to a global module
|
|
||||||
- The core module, which is always installed and provides all agents with party mode and advanced elicitation capabilities
|
- The core module, which is always installed and provides all agents with party mode and advanced elicitation capabilities
|
||||||
- Installation and update tools that work with any BMad method configuration
|
- Installation and update tools that work with any BMad method configuration
|
||||||
|
|
||||||
|
|||||||
@@ -66,19 +66,18 @@ Type "exit" or "done" to conclude the session. Participating agents will say per
|
|||||||
|
|
||||||
## Example Party Compositions
|
## Example Party Compositions
|
||||||
|
|
||||||
| Topic | Typical Agents |
|
| Topic | Typical Agents |
|
||||||
|-------|---------------|
|
| ---------------------- | ------------------------------------------------------------- |
|
||||||
| **Product Strategy** | PM + Innovation Strategist (CIS) + Analyst |
|
| **Product Strategy** | PM + Innovation Strategist (CIS) + Analyst |
|
||||||
| **Technical Design** | Architect + Creative Problem Solver (CIS) + Game Architect |
|
| **Technical Design** | Architect + Creative Problem Solver (CIS) + Game Architect |
|
||||||
| **User Experience** | UX Designer + Design Thinking Coach (CIS) + Storyteller (CIS) |
|
| **User Experience** | UX Designer + Design Thinking Coach (CIS) + Storyteller (CIS) |
|
||||||
| **Quality Assessment** | TEA + DEV + Architect |
|
| **Quality Assessment** | TEA + DEV + Architect |
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
- **Intelligent agent selection** — Selects based on expertise needed
|
- **Intelligent agent selection** — Selects based on expertise needed
|
||||||
- **Authentic personalities** — Each agent maintains their unique voice
|
- **Authentic personalities** — Each agent maintains their unique voice
|
||||||
- **Natural cross-talk** — Agents reference and build on each other
|
- **Natural cross-talk** — Agents reference and build on each other
|
||||||
- **Optional TTS** — Voice configurations for each agent
|
|
||||||
- **Graceful exit** — Personalized farewells
|
- **Graceful exit** — Personalized farewells
|
||||||
|
|
||||||
## Tips
|
## Tips
|
||||||
|
|||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"version": "6.0.0-alpha.23",
|
"version": "6.0.0-alpha.23",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@clack/prompts": "^0.11.0",
|
||||||
"@kayvan/markdown-tree-parser": "^1.6.1",
|
"@kayvan/markdown-tree-parser": "^1.6.1",
|
||||||
"boxen": "^5.1.2",
|
"boxen": "^5.1.2",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
@@ -33,7 +34,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/sitemap": "^3.6.0",
|
"@astrojs/sitemap": "^3.6.0",
|
||||||
"@astrojs/starlight": "^0.37.0",
|
"@astrojs/starlight": "^0.37.0",
|
||||||
"@clack/prompts": "^0.11.0",
|
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"astro": "^5.16.0",
|
"astro": "^5.16.0",
|
||||||
@@ -759,7 +759,6 @@
|
|||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz",
|
||||||
"integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==",
|
"integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@@ -770,7 +769,6 @@
|
|||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz",
|
||||||
"integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==",
|
"integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/core": "0.5.0",
|
"@clack/core": "0.5.0",
|
||||||
@@ -12151,7 +12149,6 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
@@ -13398,7 +13395,6 @@
|
|||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/sitemap": {
|
"node_modules/sitemap": {
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ After agent loading and introduction:
|
|||||||
- Handle missing or incomplete agent entries gracefully
|
- Handle missing or incomplete agent entries gracefully
|
||||||
- Cross-reference manifest with actual agent files
|
- Cross-reference manifest with actual agent files
|
||||||
- Prepare agent selection logic for intelligent conversation routing
|
- Prepare agent selection logic for intelligent conversation routing
|
||||||
- Set up TTS voice configurations for each agent
|
|
||||||
|
|
||||||
## NEXT STEP:
|
## NEXT STEP:
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
- 🎯 SELECT RELEVANT AGENTS based on topic analysis and expertise matching
|
- 🎯 SELECT RELEVANT AGENTS based on topic analysis and expertise matching
|
||||||
- 📋 MAINTAIN CHARACTER CONSISTENCY using merged agent personalities
|
- 📋 MAINTAIN CHARACTER CONSISTENCY using merged agent personalities
|
||||||
- 🔍 ENABLE NATURAL CROSS-TALK between agents for dynamic conversation
|
- 🔍 ENABLE NATURAL CROSS-TALK between agents for dynamic conversation
|
||||||
- 💬 INTEGRATE TTS for each agent response immediately after text
|
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
||||||
|
|
||||||
## EXECUTION PROTOCOLS:
|
## EXECUTION PROTOCOLS:
|
||||||
@@ -21,7 +20,6 @@
|
|||||||
|
|
||||||
- Complete agent roster with merged personalities is available
|
- Complete agent roster with merged personalities is available
|
||||||
- User topic and conversation history guide agent selection
|
- User topic and conversation history guide agent selection
|
||||||
- Party mode is active with TTS integration enabled
|
|
||||||
- Exit triggers: `*exit`, `goodbye`, `end party`, `quit`
|
- Exit triggers: `*exit`, `goodbye`, `end party`, `quit`
|
||||||
|
|
||||||
## YOUR TASK:
|
## YOUR TASK:
|
||||||
@@ -116,19 +114,9 @@ Allow natural back-and-forth within the same response round for dynamic interact
|
|||||||
|
|
||||||
### 6. Response Round Completion
|
### 6. Response Round Completion
|
||||||
|
|
||||||
After generating all agent responses for the round:
|
After generating all agent responses for the round, let the user know he can speak naturally with the agents, an then show this menu opion"
|
||||||
|
|
||||||
**Presentation Format:**
|
`[E] Exit Party Mode - End the collaborative session`
|
||||||
[Agent 1 Response with TTS]
|
|
||||||
[Empty line for readability]
|
|
||||||
[Agent 2 Response with TTS, potentially referencing Agent 1]
|
|
||||||
[Empty line for readability]
|
|
||||||
[Agent 3 Response with TTS, building on or offering new perspective]
|
|
||||||
|
|
||||||
**Continue Option:**
|
|
||||||
"[Agents have contributed their perspectives. Ready for more discussion?]
|
|
||||||
|
|
||||||
[E] Exit Party Mode - End the collaborative session"
|
|
||||||
|
|
||||||
### 7. Exit Condition Checking
|
### 7. Exit Condition Checking
|
||||||
|
|
||||||
@@ -142,23 +130,19 @@ Check for exit conditions before continuing:
|
|||||||
**Natural Conclusion:**
|
**Natural Conclusion:**
|
||||||
|
|
||||||
- Conversation seems naturally concluding
|
- Conversation seems naturally concluding
|
||||||
- Ask user: "Would you like to continue the discussion or end party mode?"
|
- Confirm if the user wants to exit party mode and go back to where they were or continue chatting. Do it in a conversational way with an agent in the party.
|
||||||
- Respect user choice to continue or exit
|
|
||||||
|
|
||||||
### 8. Handle Exit Selection
|
### 8. Handle Exit Selection
|
||||||
|
|
||||||
#### If 'E' (Exit Party Mode):
|
#### If 'E' (Exit Party Mode):
|
||||||
|
|
||||||
- Update frontmatter: `stepsCompleted: [1, 2]`
|
- Load read and execute: `./step-03-graceful-exit.md`
|
||||||
- Set `party_active: false`
|
|
||||||
- Load: `./step-03-graceful-exit.md`
|
|
||||||
|
|
||||||
## SUCCESS METRICS:
|
## SUCCESS METRICS:
|
||||||
|
|
||||||
✅ Intelligent agent selection based on topic analysis
|
✅ Intelligent agent selection based on topic analysis
|
||||||
✅ Authentic in-character responses maintained consistently
|
✅ Authentic in-character responses maintained consistently
|
||||||
✅ Natural cross-talk and agent interactions enabled
|
✅ Natural cross-talk and agent interactions enabled
|
||||||
✅ TTS integration working for all agent responses
|
|
||||||
✅ Question handling protocol followed correctly
|
✅ Question handling protocol followed correctly
|
||||||
✅ [E] exit option presented after each response round
|
✅ [E] exit option presented after each response round
|
||||||
✅ Conversation context and state maintained throughout
|
✅ Conversation context and state maintained throughout
|
||||||
@@ -168,7 +152,6 @@ Check for exit conditions before continuing:
|
|||||||
|
|
||||||
❌ Generic responses without character consistency
|
❌ Generic responses without character consistency
|
||||||
❌ Poor agent selection not matching topic expertise
|
❌ Poor agent selection not matching topic expertise
|
||||||
❌ Missing TTS integration for agent responses
|
|
||||||
❌ Ignoring user questions or exit triggers
|
❌ Ignoring user questions or exit triggers
|
||||||
❌ Not enabling natural agent cross-talk and interactions
|
❌ Not enabling natural agent cross-talk and interactions
|
||||||
❌ Continuing conversation without user input when questions asked
|
❌ Continuing conversation without user input when questions asked
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ workflow_completed: true
|
|||||||
|
|
||||||
- Clear any active conversation state
|
- Clear any active conversation state
|
||||||
- Reset agent selection cache
|
- Reset agent selection cache
|
||||||
- Finalize TTS session cleanup
|
|
||||||
- Mark party mode workflow as completed
|
- Mark party mode workflow as completed
|
||||||
|
|
||||||
### 6. Exit Workflow
|
### 6. Exit Workflow
|
||||||
@@ -122,7 +121,6 @@ Thank you for using BMAD Party Mode for collaborative multi-agent discussions!"
|
|||||||
✅ Satisfying agent farewells generated in authentic character voices
|
✅ Satisfying agent farewells generated in authentic character voices
|
||||||
✅ Session highlights and contributions acknowledged meaningfully
|
✅ Session highlights and contributions acknowledged meaningfully
|
||||||
✅ Positive and appreciative closure atmosphere maintained
|
✅ Positive and appreciative closure atmosphere maintained
|
||||||
✅ TTS integration working for farewell messages
|
|
||||||
✅ Frontmatter properly updated with workflow completion
|
✅ Frontmatter properly updated with workflow completion
|
||||||
✅ All workflow state cleaned up appropriately
|
✅ All workflow state cleaned up appropriately
|
||||||
✅ User left with positive impression of collaborative experience
|
✅ User left with positive impression of collaborative experience
|
||||||
|
|||||||
@@ -178,18 +178,6 @@ If conversation naturally concludes:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## TTS INTEGRATION
|
|
||||||
|
|
||||||
Party mode includes Text-to-Speech for each agent response:
|
|
||||||
|
|
||||||
**TTS Protocol:**
|
|
||||||
|
|
||||||
- Trigger TTS immediately after each agent's text response
|
|
||||||
- Use agent's merged voice configuration from manifest
|
|
||||||
- Format: `Bash: .claude/hooks/bmad-speak.sh "[Agent Name]" "[Their response]"`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## MODERATION NOTES
|
## MODERATION NOTES
|
||||||
|
|
||||||
**Quality Control:**
|
**Quality Control:**
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<rules>
|
<rules>
|
||||||
<r>ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.</r>
|
<r>ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.</r>
|
||||||
<!-- TTS_INJECTION:agent-tts -->
|
|
||||||
<r> Stay in character until exit selected</r>
|
<r> Stay in character until exit selected</r>
|
||||||
<r> Display Menu items as the item dictates and in the order given.</r>
|
<r> Display Menu items as the item dictates and in the order given.</r>
|
||||||
<r> Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml</r>
|
<r> Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml</r>
|
||||||
|
|||||||
@@ -62,40 +62,6 @@ module.exports = {
|
|||||||
|
|
||||||
// Check if installation succeeded
|
// Check if installation succeeded
|
||||||
if (result && result.success) {
|
if (result && result.success) {
|
||||||
// Run AgentVibes installer if needed
|
|
||||||
if (result.needsAgentVibes) {
|
|
||||||
// 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'));
|
|
||||||
|
|
||||||
const prompts = require('../lib/prompts');
|
|
||||||
await prompts.text({
|
|
||||||
message: chalk.green('Press Enter to start AgentVibes installer...'),
|
|
||||||
});
|
|
||||||
|
|
||||||
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'));
|
|
||||||
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:'));
|
|
||||||
console.log(chalk.green(` cd ${result.projectDir}`));
|
|
||||||
console.log(chalk.green(' npx agentvibes install\n'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display version-specific end message from install-messages.yaml
|
// Display version-specific end message from install-messages.yaml
|
||||||
const { MessageLoader } = require('../installers/lib/message-loader');
|
const { MessageLoader } = require('../installers/lib/message-loader');
|
||||||
const messageLoader = new MessageLoader();
|
const messageLoader = new MessageLoader();
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ class Installer {
|
|||||||
this.configCollector = new ConfigCollector();
|
this.configCollector = new ConfigCollector();
|
||||||
this.ideConfigManager = new IdeConfigManager();
|
this.ideConfigManager = new IdeConfigManager();
|
||||||
this.installedFiles = new Set(); // Track all installed files
|
this.installedFiles = new Set(); // Track all installed files
|
||||||
this.ttsInjectedFiles = []; // Track files with TTS injection applied
|
|
||||||
this.bmadFolderName = BMAD_FOLDER_NAME;
|
this.bmadFolderName = BMAD_FOLDER_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@ class Installer {
|
|||||||
/**
|
/**
|
||||||
* @function copyFileWithPlaceholderReplacement
|
* @function copyFileWithPlaceholderReplacement
|
||||||
* @intent Copy files from BMAD source to installation directory with dynamic content transformation
|
* @intent Copy files from BMAD source to installation directory with dynamic content transformation
|
||||||
* @why Enables installation-time customization: _bmad replacement + optional AgentVibes TTS injection
|
* @why Enables installation-time customization: _bmad replacement
|
||||||
* @param {string} sourcePath - Absolute path to source file in BMAD repository
|
* @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} targetPath - Absolute path to destination file in user's project
|
||||||
* @param {string} bmadFolderName - User's chosen bmad folder name (default: 'bmad')
|
* @param {string} bmadFolderName - User's chosen bmad folder name (default: 'bmad')
|
||||||
@@ -77,24 +76,9 @@ class Installer {
|
|||||||
* @sideeffects Writes transformed file to targetPath, creates parent directories if needed
|
* @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
|
* @edgecases Binary files bypass transformation, falls back to raw copy if UTF-8 read fails
|
||||||
* @calledby installCore(), installModule(), IDE installers during file vendoring
|
* @calledby installCore(), installModule(), IDE installers during file vendoring
|
||||||
* @calls processTTSInjectionPoints(), fs.readFile(), fs.writeFile(), fs.copy()
|
* @calls fs.readFile(), fs.writeFile(), fs.copy()
|
||||||
*
|
*
|
||||||
* 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)
|
* 3. Document marker in instructions.md (if applicable)
|
||||||
*/
|
*/
|
||||||
@@ -109,9 +93,6 @@ class Installer {
|
|||||||
// Read the file content
|
// Read the file content
|
||||||
let content = await fs.readFile(sourcePath, 'utf8');
|
let content = await fs.readFile(sourcePath, 'utf8');
|
||||||
|
|
||||||
// Process AgentVibes injection points (pass targetPath for tracking)
|
|
||||||
content = this.processTTSInjectionPoints(content, targetPath);
|
|
||||||
|
|
||||||
// Write to target with replaced content
|
// Write to target with replaced content
|
||||||
await fs.ensureDir(path.dirname(targetPath));
|
await fs.ensureDir(path.dirname(targetPath));
|
||||||
await fs.writeFile(targetPath, content, 'utf8');
|
await fs.writeFile(targetPath, content, 'utf8');
|
||||||
@@ -125,116 +106,6 @@ 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, targetPath = null) {
|
|
||||||
// Check if AgentVibes is enabled (set during installation configuration)
|
|
||||||
const enableAgentVibes = this.enableAgentVibes || false;
|
|
||||||
|
|
||||||
// Check if content contains any TTS injection markers
|
|
||||||
const hasPartyMode = content.includes('<!-- TTS_INJECTION:party-mode -->');
|
|
||||||
const hasAgentTTS = content.includes('<!-- TTS_INJECTION:agent-tts -->');
|
|
||||||
|
|
||||||
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`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Track files that had TTS injection applied
|
|
||||||
if (targetPath && (hasPartyMode || hasAgentTTS)) {
|
|
||||||
const injectionType = hasPartyMode ? 'party-mode' : 'agent-tts';
|
|
||||||
this.ttsInjectedFiles.push({ path: targetPath, type: injectionType });
|
|
||||||
}
|
|
||||||
} 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
|
* Collect Tool/IDE configurations after module configuration
|
||||||
* @param {string} projectDir - Project directory
|
* @param {string} projectDir - Project directory
|
||||||
@@ -251,7 +122,7 @@ class Installer {
|
|||||||
// Fallback: prompt for tool selection (backwards compatibility)
|
// Fallback: prompt for tool selection (backwards compatibility)
|
||||||
const { UI } = require('../../../lib/ui');
|
const { UI } = require('../../../lib/ui');
|
||||||
const ui = new UI();
|
const ui = new UI();
|
||||||
toolConfig = await ui.promptToolSelection(projectDir, selectedModules);
|
toolConfig = await ui.promptToolSelection(projectDir);
|
||||||
} else {
|
} else {
|
||||||
// IDEs were already selected during initial prompts
|
// IDEs were already selected during initial prompts
|
||||||
toolConfig = {
|
toolConfig = {
|
||||||
@@ -510,9 +381,6 @@ class Installer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Set bmad folder name on module manager and IDE manager for placeholder replacement
|
||||||
this.moduleManager.setBmadFolderName(BMAD_FOLDER_NAME);
|
this.moduleManager.setBmadFolderName(BMAD_FOLDER_NAME);
|
||||||
this.moduleManager.setCoreConfig(moduleConfigs.core || {});
|
this.moduleManager.setCoreConfig(moduleConfigs.core || {});
|
||||||
@@ -1234,8 +1102,6 @@ class Installer {
|
|||||||
modules: config.modules,
|
modules: config.modules,
|
||||||
ides: config.ides,
|
ides: config.ides,
|
||||||
customFiles: customFiles.length > 0 ? customFiles : undefined,
|
customFiles: customFiles.length > 0 ? customFiles : undefined,
|
||||||
ttsInjectedFiles: this.enableAgentVibes && this.ttsInjectedFiles.length > 0 ? this.ttsInjectedFiles : undefined,
|
|
||||||
agentVibesEnabled: this.enableAgentVibes || false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -1243,7 +1109,6 @@ class Installer {
|
|||||||
path: bmadDir,
|
path: bmadDir,
|
||||||
modules: config.modules,
|
modules: config.modules,
|
||||||
ides: config.ides,
|
ides: config.ides,
|
||||||
needsAgentVibes: this.enableAgentVibes && !config.agentVibesInstalled,
|
|
||||||
projectDir: projectDir,
|
projectDir: projectDir,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -845,14 +845,8 @@ class ModuleManager {
|
|||||||
// Compile with customizations if any
|
// Compile with customizations if any
|
||||||
const { xml } = await compileAgent(yamlContent, answers, agentName, relativePath, { config: this.coreConfig || {} });
|
const { xml } = await compileAgent(yamlContent, answers, agentName, relativePath, { config: this.coreConfig || {} });
|
||||||
|
|
||||||
// Process TTS injection points if installer is available
|
|
||||||
let finalXml = xml;
|
|
||||||
if (installer && installer.processTTSInjectionPoints) {
|
|
||||||
finalXml = installer.processTTSInjectionPoints(xml, targetMdPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the compiled agent
|
// Write the compiled agent
|
||||||
await fs.writeFile(targetMdPath, finalXml, 'utf8');
|
await fs.writeFile(targetMdPath, xml, 'utf8');
|
||||||
|
|
||||||
// Handle sidecar copying if present
|
// Handle sidecar copying if present
|
||||||
if (hasSidecar) {
|
if (hasSidecar) {
|
||||||
|
|||||||
@@ -478,39 +478,10 @@ function filterCustomizationData(data) {
|
|||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Process TTS injection markers in content
|
|
||||||
* @param {string} content - Content to process
|
|
||||||
* @param {boolean} enableAgentVibes - Whether AgentVibes is enabled
|
|
||||||
* @returns {Object} { content: string, hadInjection: boolean }
|
|
||||||
*/
|
|
||||||
function processTTSInjectionPoints(content, enableAgentVibes) {
|
|
||||||
const hasAgentTTS = content.includes('<!-- TTS_INJECTION:agent-tts -->');
|
|
||||||
|
|
||||||
if (enableAgentVibes && hasAgentTTS) {
|
|
||||||
// Replace agent-tts injection marker with TTS rule
|
|
||||||
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`,
|
|
||||||
);
|
|
||||||
return { content, hadInjection: true };
|
|
||||||
} else if (!enableAgentVibes && hasAgentTTS) {
|
|
||||||
// Strip injection markers when disabled
|
|
||||||
content = content.replaceAll(/<!-- TTS_INJECTION:agent-tts -->\n?/g, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return { content, hadInjection: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile agent file to .md
|
* Compile agent file to .md
|
||||||
* @param {string} yamlPath - Path to agent YAML file
|
* @param {string} yamlPath - Path to agent YAML file
|
||||||
* @param {Object} options - { answers: {}, outputPath: string, enableAgentVibes: boolean }
|
* @param {Object} options - { answers: {}, outputPath: string }
|
||||||
* @returns {Object} Compilation result
|
* @returns {Object} Compilation result
|
||||||
*/
|
*/
|
||||||
function compileAgentFile(yamlPath, options = {}) {
|
function compileAgentFile(yamlPath, options = {}) {
|
||||||
@@ -526,15 +497,6 @@ function compileAgentFile(yamlPath, options = {}) {
|
|||||||
outputPath = path.join(dir, `${basename}.md`);
|
outputPath = path.join(dir, `${basename}.md`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process TTS injection points if enableAgentVibes option is provided
|
|
||||||
let xml = result.xml;
|
|
||||||
let ttsInjected = false;
|
|
||||||
if (options.enableAgentVibes !== undefined) {
|
|
||||||
const ttsResult = processTTSInjectionPoints(xml, options.enableAgentVibes);
|
|
||||||
xml = ttsResult.content;
|
|
||||||
ttsInjected = ttsResult.hadInjection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write compiled XML
|
// Write compiled XML
|
||||||
fs.writeFileSync(outputPath, xml, 'utf8');
|
fs.writeFileSync(outputPath, xml, 'utf8');
|
||||||
|
|
||||||
@@ -543,7 +505,6 @@ function compileAgentFile(yamlPath, options = {}) {
|
|||||||
xml,
|
xml,
|
||||||
outputPath,
|
outputPath,
|
||||||
sourcePath: yamlPath,
|
sourcePath: yamlPath,
|
||||||
ttsInjected,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,32 +171,6 @@ class UI {
|
|||||||
// Check if there's an existing BMAD installation (after any folder renames)
|
// Check if there's an existing BMAD installation (after any folder renames)
|
||||||
const hasExistingInstall = await fs.pathExists(bmadDir);
|
const hasExistingInstall = await fs.pathExists(bmadDir);
|
||||||
|
|
||||||
// Collect IDE tool selection early - we need this to know if we should ask about TTS
|
|
||||||
let toolSelection;
|
|
||||||
let agentVibesConfig = { enabled: false, alreadyInstalled: false };
|
|
||||||
let claudeCodeSelected = false;
|
|
||||||
|
|
||||||
if (!hasExistingInstall) {
|
|
||||||
// For new installations, collect IDE selection first
|
|
||||||
// We don't have modules yet, so pass empty array
|
|
||||||
toolSelection = await this.promptToolSelection(confirmedDirectory, []);
|
|
||||||
|
|
||||||
// Check if Claude Code was selected
|
|
||||||
claudeCodeSelected = toolSelection.ides && toolSelection.ides.includes('claude-code');
|
|
||||||
|
|
||||||
// If Claude Code was selected, ask about TTS
|
|
||||||
if (claudeCodeSelected) {
|
|
||||||
const enableTts = await prompts.confirm({
|
|
||||||
message: 'Claude Code supports TTS (Text-to-Speech). Would you like to enable it?',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (enableTts) {
|
|
||||||
agentVibesConfig = { enabled: true, alreadyInstalled: false };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let customContentConfig = { hasCustomContent: false };
|
let customContentConfig = { hasCustomContent: false };
|
||||||
if (!hasExistingInstall) {
|
if (!hasExistingInstall) {
|
||||||
customContentConfig._shouldAsk = true;
|
customContentConfig._shouldAsk = true;
|
||||||
@@ -324,20 +298,8 @@ class UI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get tool selection
|
// Get tool selection
|
||||||
const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
const toolSelection = await this.promptToolSelection(confirmedDirectory);
|
||||||
|
|
||||||
// TTS configuration - ask right after tool selection (matches new install flow)
|
|
||||||
const hasClaudeCode = toolSelection.ides && toolSelection.ides.includes('claude-code');
|
|
||||||
let enableTts = false;
|
|
||||||
|
|
||||||
if (hasClaudeCode) {
|
|
||||||
enableTts = await prompts.confirm({
|
|
||||||
message: 'Claude Code supports TTS (Text-to-Speech). Would you like to enable it?',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Core config with existing defaults (ask after TTS)
|
|
||||||
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -349,8 +311,6 @@ class UI {
|
|||||||
skipIde: toolSelection.skipIde,
|
skipIde: toolSelection.skipIde,
|
||||||
coreConfig: coreConfig,
|
coreConfig: coreConfig,
|
||||||
customContent: customModuleResult.customContentConfig,
|
customContent: customModuleResult.customContentConfig,
|
||||||
enableAgentVibes: enableTts,
|
|
||||||
agentVibesInstalled: false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,7 +332,7 @@ class UI {
|
|||||||
|
|
||||||
// Ask about custom content
|
// Ask about custom content
|
||||||
const wantsCustomContent = await prompts.confirm({
|
const wantsCustomContent = await prompts.confirm({
|
||||||
message: 'Would you like to install a local custom module (this includes custom agents and workflows also)?',
|
message: 'Would you like to install a locally stored custom module (this includes custom agents and workflows also)?',
|
||||||
default: false,
|
default: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -391,19 +351,10 @@ class UI {
|
|||||||
selectedModules = [...selectedModules, ...customContentConfig.selectedModuleIds];
|
selectedModules = [...selectedModules, ...customContentConfig.selectedModuleIds];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove core if it's in the list (it's always installed)
|
|
||||||
selectedModules = selectedModules.filter((m) => m !== 'core');
|
selectedModules = selectedModules.filter((m) => m !== 'core');
|
||||||
|
let toolSelection = await this.promptToolSelection(confirmedDirectory);
|
||||||
// Tool selection (already done for new installs at the beginning)
|
|
||||||
if (!toolSelection) {
|
|
||||||
toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect configurations for new installations
|
|
||||||
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
||||||
|
|
||||||
// TTS already handled at the beginning for new installs
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
actionType: 'install',
|
actionType: 'install',
|
||||||
directory: confirmedDirectory,
|
directory: confirmedDirectory,
|
||||||
@@ -413,18 +364,15 @@ class UI {
|
|||||||
skipIde: toolSelection.skipIde,
|
skipIde: toolSelection.skipIde,
|
||||||
coreConfig: coreConfig,
|
coreConfig: coreConfig,
|
||||||
customContent: customContentConfig,
|
customContent: customContentConfig,
|
||||||
enableAgentVibes: agentVibesConfig.enabled,
|
|
||||||
agentVibesInstalled: agentVibesConfig.alreadyInstalled,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompt for tool/IDE selection (called after module configuration)
|
* Prompt for tool/IDE selection (called after module configuration)
|
||||||
* @param {string} projectDir - Project directory to check for existing IDEs
|
* @param {string} projectDir - Project directory to check for existing IDEs
|
||||||
* @param {Array} selectedModules - Selected modules from configuration
|
|
||||||
* @returns {Object} Tool configuration
|
* @returns {Object} Tool configuration
|
||||||
*/
|
*/
|
||||||
async promptToolSelection(projectDir, selectedModules) {
|
async promptToolSelection(projectDir) {
|
||||||
// Check for existing configured IDEs - use findBmadDir to detect custom folder names
|
// Check for existing configured IDEs - use findBmadDir to detect custom folder names
|
||||||
const { Detector } = require('../installers/lib/core/detector');
|
const { Detector } = require('../installers/lib/core/detector');
|
||||||
const { Installer } = require('../installers/lib/core/installer');
|
const { Installer } = require('../installers/lib/core/installer');
|
||||||
@@ -608,25 +556,6 @@ class UI {
|
|||||||
if (result.modules && result.modules.length > 0) {
|
if (result.modules && result.modules.length > 0) {
|
||||||
console.log(chalk.dim(`Modules: ${result.modules.join(', ')}`));
|
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!'));
|
|
||||||
|
|
||||||
// Add changelog link at the end
|
|
||||||
console.log(
|
|
||||||
chalk.magenta(
|
|
||||||
"\n📋 Want to see what's new? Check out the changelog: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1061,136 +990,6 @@ class UI {
|
|||||||
return path.resolve(expanded);
|
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(), prompts.select(), chalk.green/yellow/dim()
|
|
||||||
*
|
|
||||||
* AI NOTE: This prompt is strategically positioned in installation flow:
|
|
||||||
* - AFTER core config (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 enableTts = await prompts.confirm({
|
|
||||||
message: 'Enable Agents to Speak Out loud (powered by Agent Vibes? Claude Code only currently)',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (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: 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load existing configurations to use as defaults
|
* Load existing configurations to use as defaults
|
||||||
* @param {string} directory - Installation directory
|
* @param {string} directory - Installation directory
|
||||||
@@ -1201,7 +1000,6 @@ class UI {
|
|||||||
hasCustomContent: false,
|
hasCustomContent: false,
|
||||||
coreConfig: {},
|
coreConfig: {},
|
||||||
ideConfig: { ides: [], skipIde: false },
|
ideConfig: { ides: [], skipIde: false },
|
||||||
agentVibesConfig: { enabled: false, alreadyInstalled: false },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1215,10 +1013,6 @@ class UI {
|
|||||||
configs.ideConfig.skipIde = false;
|
configs.ideConfig.skipIde = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load AgentVibes configuration
|
|
||||||
const agentVibesInstalled = await this.checkAgentVibesInstalled(directory);
|
|
||||||
configs.agentVibesConfig = { enabled: agentVibesInstalled, alreadyInstalled: agentVibesInstalled };
|
|
||||||
|
|
||||||
return configs;
|
return configs;
|
||||||
} catch {
|
} catch {
|
||||||
// If loading fails, return empty configs
|
// If loading fails, return empty configs
|
||||||
|
|||||||
Reference in New Issue
Block a user