Merge branch 'kiro-cli-installer' of https://github.com/igknot/BMAD-METHOD into kiro-cli-installer

This commit is contained in:
Philip Louw 2025-11-27 10:17:18 +02:00
commit 9909f0c5ae
33 changed files with 3163 additions and 1939 deletions

1
.gitignore vendored
View File

@ -70,3 +70,4 @@ z*/
.codex .codex
.github/chatmodes .github/chatmodes
.agent .agent
.agentvibes/

115
TESTING.md Normal file
View File

@ -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
```

388
docs/ide-info/rovo-dev.md Normal file
View File

@ -0,0 +1,388 @@
# Rovo Dev IDE Integration
This document describes how BMAD-METHOD integrates with [Atlassian Rovo Dev](https://www.atlassian.com/rovo-dev), an AI-powered software development assistant.
## Overview
Rovo Dev is designed to integrate deeply with developer workflows and organizational knowledge bases. When you install BMAD-METHOD in a Rovo Dev project, it automatically installs BMAD agents, workflows, tasks, and tools just like it does for other IDEs (Cursor, VS Code, etc.).
BMAD-METHOD provides:
- **Agents**: Specialized subagents for various development tasks
- **Workflows**: Multi-step workflow guides and coordinators
- **Tasks & Tools**: Reference documentation for BMAD tasks and tools
### What are Rovo Dev Subagents?
Subagents are specialized agents that Rovo Dev can delegate tasks to. They are defined as Markdown files with YAML frontmatter stored in the `.rovodev/subagents/` directory. Rovo Dev automatically discovers these files and makes them available through the `@subagent-name` syntax.
## Installation and Setup
### Automatic Installation
When you run the BMAD-METHOD installer and select Rovo Dev as your IDE:
```bash
bmad install
```
The installer will:
1. Create a `.rovodev/subagents/` directory in your project (if it doesn't exist)
2. Convert BMAD agents into Rovo Dev subagent format
3. Write subagent files with the naming pattern: `bmad-<module>-<agent-name>.md`
### File Structure
After installation, your project will have:
```
project-root/
├── .rovodev/
│ ├── subagents/
│ │ ├── bmad-core-code-reviewer.md
│ │ ├── bmad-bmm-pm.md
│ │ ├── bmad-bmm-dev.md
│ │ └── ... (more agents from selected modules)
│ ├── workflows/
│ │ ├── bmad-brainstorming.md
│ │ ├── bmad-prd-creation.md
│ │ └── ... (workflow guides)
│ ├── references/
│ │ ├── bmad-task-core-code-review.md
│ │ ├── bmad-tool-core-analysis.md
│ │ └── ... (task/tool references)
│ ├── config.yml (Rovo Dev configuration)
│ ├── prompts.yml (Optional: reusable prompts)
│ └── ...
├── .bmad/ (BMAD installation directory)
└── ...
```
**Directory Structure Explanation:**
- **subagents/**: Agents discovered and used by Rovo Dev with `@agent-name` syntax
- **workflows/**: Multi-step workflow guides and instructions
- **references/**: Documentation for available tasks and tools in BMAD
## Subagent File Format
BMAD agents are converted to Rovo Dev subagent format, which uses Markdown with YAML frontmatter:
### Basic Structure
```markdown
---
name: bmad-module-agent-name
description: One sentence description of what this agent does
tools:
- bash
- open_files
- grep
- expand_code_chunks
model: anthropic.claude-3-5-sonnet-20241022-v2:0 # Optional
load_memory: true # Optional
---
You are a specialized agent for [specific task].
## Your Role
Describe the agent's role and responsibilities...
## Key Instructions
1. First instruction
2. Second instruction
3. Third instruction
## When to Use This Agent
Explain when and how to use this agent...
```
### YAML Frontmatter Fields
| Field | Type | Required | Description |
| ------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Unique identifier for the subagent (kebab-case, no spaces) |
| `description` | string | Yes | One-line description of the subagent's purpose |
| `tools` | array | No | List of tools the subagent can use. If not specified, uses parent agent's tools |
| `model` | string | No | Specific LLM model for this subagent (e.g., `anthropic.claude-3-5-sonnet-20241022-v2:0`). If not specified, uses parent agent's model |
| `load_memory` | boolean | No | Whether to load default memory files (AGENTS.md, AGENTS.local.md). Defaults to `true` |
### System Prompt
The content after the closing `---` is the subagent's system prompt. This defines:
- The agent's persona and role
- Its capabilities and constraints
- Step-by-step instructions for task execution
- Examples of expected behavior
## Using BMAD Components in Rovo Dev
### Invoking a Subagent (Agent)
In Rovo Dev, you can invoke a BMAD agent as a subagent using the `@` syntax:
```
@bmad-core-code-reviewer Please review this PR for potential issues
@bmad-bmm-pm Help plan this feature release
@bmad-bmm-dev Implement this feature
```
### Accessing Workflows
Workflow guides are available in `.rovodev/workflows/` directory:
```
@bmad-core-code-reviewer Use the brainstorming workflow from .rovodev/workflows/bmad-brainstorming.md
```
Workflow files contain step-by-step instructions and can be referenced or copied into Rovo Dev for collaborative workflow execution.
### Accessing Tasks and Tools
Task and tool documentation is available in `.rovodev/references/` directory. These provide:
- Task execution instructions
- Tool capabilities and usage
- Integration examples
- Parameter documentation
### Example Usage Scenarios
#### Code Review
```
@bmad-core-code-reviewer Review the changes in src/components/Button.tsx
for best practices, performance, and potential bugs
```
#### Documentation
```
@bmad-core-documentation-writer Generate API documentation for the new
user authentication module
```
#### Feature Design
```
@bmad-module-feature-designer Design a solution for implementing
dark mode support across the application
```
## Customizing BMAD Subagents
You can customize BMAD subagents after installation by editing their files directly in `.rovodev/subagents/`.
### Example: Adding Tool Restrictions
By default, BMAD subagents inherit tools from the parent Rovo Dev agent. You can restrict which tools a specific subagent can use:
```yaml
---
name: bmad-core-code-reviewer
description: Reviews code and suggests improvements
tools:
- open_files
- expand_code_chunks
- grep
---
```
### Example: Using a Specific Model
Some agents might benefit from using a different model. You can specify this:
```yaml
---
name: bmad-core-documentation-writer
description: Writes clear and comprehensive documentation
model: anthropic.claude-3-5-sonnet-20241022-v2:0
---
```
### Example: Enhancing the System Prompt
You can add additional context to a subagent's system prompt:
```markdown
---
name: bmad-core-code-reviewer
description: Reviews code and suggests improvements
---
You are a specialized code review agent for our project.
## Project Context
Our codebase uses:
- React 18 for frontend
- Node.js 18+ for backend
- TypeScript for type safety
- Jest for testing
## Review Checklist
1. Type safety and TypeScript correctness
2. React best practices and hooks usage
3. Performance considerations
4. Test coverage
5. Documentation and comments
...rest of original system prompt...
```
## Memory and Context
By default, BMAD subagents have `load_memory: true`, which means they will load memory files from your project:
- **Project-level**: `.rovodev/AGENTS.md` and `.rovodev/.agent.md`
- **User-level**: `~/.rovodev/AGENTS.md` (global memory across all projects)
These files can contain:
- Project guidelines and conventions
- Common patterns and best practices
- Recent decisions and context
- Custom instructions for all agents
### Creating Project Memory
Create `.rovodev/AGENTS.md` in your project:
```markdown
# Project Guidelines
## Code Style
- Use 2-space indentation
- Use camelCase for variables
- Use PascalCase for classes
## Architecture
- Follow modular component structure
- Use dependency injection for services
- Implement proper error handling
## Testing Requirements
- Minimum 80% code coverage
- Write tests before implementation
- Use descriptive test names
```
## Troubleshooting
### Subagents Not Appearing in Rovo Dev
1. **Verify files exist**: Check that `.rovodev/subagents/bmad-*.md` files are present
2. **Check Rovo Dev is reloaded**: Rovo Dev may cache agent definitions. Restart Rovo Dev or reload the project
3. **Verify file format**: Ensure files have proper YAML frontmatter (between `---` markers)
4. **Check file permissions**: Ensure files are readable by Rovo Dev
### Agent Name Conflicts
If you have custom subagents with the same names as BMAD agents, Rovo Dev will load both but may show a warning. Use unique prefixes for custom subagents to avoid conflicts.
### Tools Not Available
If a subagent's tools aren't working:
1. Verify the tool names match Rovo Dev's available tools
2. Check that the parent Rovo Dev agent has access to those tools
3. Ensure tool permissions are properly configured in `.rovodev/config.yml`
## Advanced: Tool Configuration
Rovo Dev agents have access to a set of tools for various tasks. Common tools available include:
- `bash`: Execute shell commands
- `open_files`: View file contents
- `grep`: Search across files
- `expand_code_chunks`: View specific code sections
- `find_and_replace_code`: Modify files
- `create_file`: Create new files
- `delete_file`: Delete files
- `move_file`: Rename or move files
### MCP Servers
Rovo Dev can also connect to Model Context Protocol (MCP) servers, which provide additional tools and data sources:
- **Atlassian Integration**: Access to Jira, Confluence, and Bitbucket
- **Code Analysis**: Custom code analysis and metrics
- **External Services**: APIs and third-party integrations
Configure MCP servers in `~/.rovodev/mcp.json` or `.rovodev/mcp.json`.
## Integration with Other IDE Handlers
BMAD-METHOD supports multiple IDEs simultaneously. You can have both Rovo Dev and other IDE configurations (Cursor, VS Code, etc.) in the same project. Each IDE will have its own artifacts installed in separate directories.
For example:
- Rovo Dev agents: `.rovodev/subagents/bmad-*.md`
- Cursor rules: `.cursor/rules/bmad/`
- Claude Code: `.claude/rules/bmad/`
## Performance Considerations
- BMAD subagent files are typically small (1-5 KB each)
- Rovo Dev lazy-loads subagents, so having many subagents doesn't impact startup time
- System prompts are cached by Rovo Dev after first load
## Best Practices
1. **Keep System Prompts Concise**: Shorter, well-structured prompts are more effective
2. **Use Project Memory**: Leverage `.rovodev/AGENTS.md` for shared context
3. **Customize Tool Restrictions**: Give subagents only the tools they need
4. **Test Subagent Invocations**: Verify each subagent works as expected for your project
5. **Version Control**: Commit `.rovodev/subagents/` to version control for team consistency
6. **Document Custom Subagents**: Add comments explaining the purpose of customized subagents
## Related Documentation
- [Rovo Dev Official Documentation](https://www.atlassian.com/rovo-dev)
- [BMAD-METHOD Installation Guide](./installation.md)
- [IDE Handler Architecture](./ide-handlers.md)
- [Rovo Dev Configuration Reference](https://www.atlassian.com/rovo-dev/configuration)
## Examples
### Example 1: Code Review Workflow
```
User: @bmad-core-code-reviewer Review src/auth/login.ts for security issues
Rovo Dev → Subagent: Opens file, analyzes code, suggests improvements
Subagent output: Security vulnerabilities found, recommendations provided
```
### Example 2: Documentation Generation
```
User: @bmad-core-documentation-writer Generate API docs for the new payment module
Rovo Dev → Subagent: Analyzes code structure, generates documentation
Subagent output: Markdown documentation with examples and API reference
```
### Example 3: Architecture Design
```
User: @bmad-module-feature-designer Design a caching strategy for the database layer
Rovo Dev → Subagent: Reviews current architecture, proposes design
Subagent output: Detailed architecture proposal with implementation plan
```
## Support
For issues or questions about:
- **Rovo Dev**: See [Atlassian Rovo Dev Documentation](https://www.atlassian.com/rovo-dev)
- **BMAD-METHOD**: See [BMAD-METHOD README](../README.md)
- **IDE Integration**: See [IDE Handler Guide](./ide-handlers.md)

View File

@ -87,6 +87,7 @@ Instructions for loading agents and running workflows in your development enviro
- [OpenCode](./ide-info/opencode.md) - [OpenCode](./ide-info/opencode.md)
- [Qwen](./ide-info/qwen.md) - [Qwen](./ide-info/qwen.md)
- [Roo](./ide-info/roo.md) - [Roo](./ide-info/roo.md)
- [Rovo Dev](./ide-info/rovo-dev.md)
- [Trae](./ide-info/trae.md) - [Trae](./ide-info/trae.md)
**Key concept:** Every reference to "load an agent" or "activate an agent" in the main docs links to the [ide-info](./ide-info/) directory for IDE-specific instructions. **Key concept:** Every reference to "load an agent" or "activate an agent" in the main docs links to the [ide-info](./ide-info/) directory for IDE-specific instructions.

View File

@ -171,7 +171,7 @@ communication_language: "English"
- Windsurf - Windsurf
**Additional**: **Additional**:
Cline, Roo, Auggie, GitHub Copilot, Codex, Gemini, Qwen, Trae, Kilo, Crush, iFlow Cline, Roo, Rovo Dev,Auggie, GitHub Copilot, Codex, Gemini, Qwen, Trae, Kilo, Crush, iFlow
### Platform Features ### Platform Features

54
package-lock.json generated
View File

@ -1023,9 +1023,9 @@
} }
}, },
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
"version": "3.14.1", "version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1329,9 +1329,9 @@
} }
}, },
"node_modules/@jest/reporters/node_modules/glob": { "node_modules/@jest/reporters/node_modules/glob": {
"version": "10.4.5", "version": "10.5.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@ -2618,9 +2618,9 @@
} }
}, },
"node_modules/c8/node_modules/glob": { "node_modules/c8/node_modules/glob": {
"version": "10.4.5", "version": "10.5.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@ -4103,14 +4103,14 @@
} }
}, },
"node_modules/glob": { "node_modules/glob": {
"version": "11.0.3", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
"integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
"license": "ISC", "license": "BlueOak-1.0.0",
"dependencies": { "dependencies": {
"foreground-child": "^3.3.1", "foreground-child": "^3.3.1",
"jackspeak": "^4.1.1", "jackspeak": "^4.1.1",
"minimatch": "^10.0.3", "minimatch": "^10.1.1",
"minipass": "^7.1.2", "minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0", "package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0" "path-scurry": "^2.0.0"
@ -4139,10 +4139,10 @@
} }
}, },
"node_modules/glob/node_modules/minimatch": { "node_modules/glob/node_modules/minimatch": {
"version": "10.0.3", "version": "10.1.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==",
"license": "ISC", "license": "BlueOak-1.0.0",
"dependencies": { "dependencies": {
"@isaacs/brace-expansion": "^5.0.0" "@isaacs/brace-expansion": "^5.0.0"
}, },
@ -4808,9 +4808,9 @@
} }
}, },
"node_modules/jest-config/node_modules/glob": { "node_modules/jest-config/node_modules/glob": {
"version": "10.4.5", "version": "10.5.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@ -5181,9 +5181,9 @@
} }
}, },
"node_modules/jest-runtime/node_modules/glob": { "node_modules/jest-runtime/node_modules/glob": {
"version": "10.4.5", "version": "10.5.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@ -5413,9 +5413,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"

View File

@ -3,6 +3,8 @@
<critical>The workflow execution engine is governed by: {project_root}/{bmad_folder}/core/tasks/workflow.xml</critical> <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> <critical>This workflow orchestrates group discussions between all installed BMAD agents</critical>
<!-- TTS_INJECTION:party-mode -->
<workflow> <workflow>
<step n="1" goal="Load Agent Manifest and Configurations"> <step n="1" goal="Load Agent Manifest and Configurations">
@ -94,17 +96,29 @@
</substep> </substep>
<substep n="3d" goal="Format and Present Responses"> <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>
<!-- TTS_INJECTION:party-mode -->
<format> <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> </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>Maintain spacing between agents for readability</action>
<action>Preserve each agent's unique voice throughout</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> </substep>

View File

@ -1 +0,0 @@
# BMad Method Master Knowledge Base Index

View File

@ -1,30 +0,0 @@
# Technical Decisions Log
_Auto-updated during discovery and planning sessions - you can also add information here yourself_
## Purpose
This document captures technical decisions, preferences, and constraints discovered during project discussions. It serves as input for architecture.md and solution design documents.
## Confirmed Decisions
<!-- Technical choices explicitly confirmed by the team/user -->
## Preferences
<!-- Non-binding preferences mentioned during discussions -->
## Constraints
<!-- Hard requirements from infrastructure, compliance, or integration needs -->
## To Investigate
<!-- Technical questions that need research or architect input -->
## Notes
- This file is automatically updated when technical information is mentioned
- Decisions here are inputs, not final architecture
- Final technical decisions belong in architecture.md
- Implementation details belong in solutions/\*.md and story context or dev notes.

View File

@ -18,21 +18,25 @@ agent:
- Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md` - Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`
menu: menu:
- trigger: workflow-status
workflow: "{project-root}/{bmad_folder}/bmm/workflows/workflow-status/workflow.yaml"
description: Get workflow status or initialize a workflow if not already done (optional)
- trigger: brainstorm-project - trigger: brainstorm-project
workflow: "{project-root}/{bmad_folder}/bmm/workflows/1-analysis/brainstorm-project/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/1-analysis/brainstorm-project/workflow.yaml"
description: Guided Brainstorming scoped to product development ideation and problem discovery description: Guided Brainstorming session with final report (optional)
- trigger: research - trigger: research
workflow: "{project-root}/{bmad_folder}/bmm/workflows/1-analysis/research/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/1-analysis/research/workflow.yaml"
description: Guided Research scoped to market and competitive analysis of a product or feature description: Guided Research scoped to market and competitive analysis (optional)
- trigger: product-brief - trigger: product-brief
workflow: "{project-root}/{bmad_folder}/bmm/workflows/1-analysis/product-brief/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/1-analysis/product-brief/workflow.yaml"
description: Create a Product Brief, a great input to then drive a PRD description: Create a Product Brief (recommended input for PRD)
- trigger: document-project - trigger: document-project
workflow: "{project-root}/{bmad_folder}/bmm/workflows/document-project/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/document-project/workflow.yaml"
description: Generate comprehensive documentation of an existing codebase, including architecture, data flows, and API contracts, and other details to aid project understanding. description: Document your existing project (optional, but recommended for existing brownfield project efforts)
- trigger: party-mode - trigger: party-mode
workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml" workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml"

View File

@ -18,25 +18,29 @@ agent:
- Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md` - Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`
menu: menu:
- trigger: workflow-status
workflow: "{project-root}/{bmad_folder}/bmm/workflows/workflow-status/workflow.yaml"
description: Get workflow status or initialize a workflow if not already done (optional)
- trigger: create-architecture - trigger: create-architecture
workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/architecture/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/architecture/workflow.yaml"
description: Produce a Scale Adaptive Architecture description: Create an Architecture Document to Guide Development of a PRD (required for BMad Method projects)
- trigger: validate-architecture - trigger: validate-architecture
validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/architecture/workflow.yaml" validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/architecture/workflow.yaml"
description: Validate Architecture Document description: Validate Architecture Document (Recommended, use another LLM and fresh context for best results)
- trigger: implementation-readiness - trigger: implementation-readiness
workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/implementation-readiness/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/implementation-readiness/workflow.yaml"
description: Validate implementation readiness - PRD, UX, Architecture, Epics aligned description: Validate PRD, UX, Architecture, Epics and stories aligned (Optional but recommended before development)
- trigger: create-excalidraw-diagram - trigger: create-excalidraw-diagram
workflow: "{project-root}/{bmad_folder}/bmm/workflows/diagrams/create-diagram/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/diagrams/create-diagram/workflow.yaml"
description: Create system architecture or technical diagram (Excalidraw) description: Create system architecture or technical diagram (Excalidraw) (Use any time you need a diagram)
- trigger: create-excalidraw-dataflow - trigger: create-excalidraw-dataflow
workflow: "{project-root}/{bmad_folder}/bmm/workflows/diagrams/create-dataflow/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/diagrams/create-dataflow/workflow.yaml"
description: Create data flow diagram (Excalidraw) description: Create data flow diagram (Excalidraw) (Use any time you need a diagram)
- trigger: party-mode - trigger: party-mode
workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml" workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml"

View File

@ -39,10 +39,6 @@ agent:
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/dev-story/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/dev-story/workflow.yaml"
description: "Execute Dev Story workflow (full BMM path with sprint-status)" description: "Execute Dev Story workflow (full BMM path with sprint-status)"
- trigger: story-done
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/story-done/workflow.yaml"
description: "Mark story done after DoD complete"
- trigger: code-review - trigger: code-review
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/code-review/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/code-review/workflow.yaml"
description: "Perform a thorough clean context QA code review on a story flagged Ready for Review" description: "Perform a thorough clean context code review (Highly Recommended, use fresh context and different LLM)"

View File

@ -19,21 +19,25 @@ agent:
- Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md` - Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`
menu: menu:
- trigger: workflow-status
workflow: "{project-root}/{bmad_folder}/bmm/workflows/workflow-status/workflow.yaml"
description: Get workflow status or initialize a workflow if not already done (optional)
- trigger: create-prd - trigger: create-prd
workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/prd/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/prd/workflow.yaml"
description: Create Product Requirements Document (PRD) description: Create Product Requirements Document (PRD) (Required for BMad Method flow)
- trigger: validate-prd - trigger: validate-prd
validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/prd/workflow.yaml" validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/prd/workflow.yaml"
description: Validate PRD description: Validate PRD (Highly Recommended, use fresh context and different LLM for best results)
- trigger: create-epics-and-stories - trigger: create-epics-and-stories
workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.yaml"
description: Create Epics and User Stories from PRD (Its recommended to not do this until the architecture is complete) description: Create Epics and User Stories from PRD (Required for BMad Method flow AFTER the Architecture is completed)
- trigger: correct-course - trigger: correct-course
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/correct-course/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/correct-course/workflow.yaml"
description: Course Correction Analysis description: Course Correction Analysis (optional during implementation when things go off track)
ide-only: true ide-only: true
- trigger: party-mode - trigger: party-mode

View File

@ -21,15 +21,15 @@ agent:
menu: menu:
- trigger: create-tech-spec - trigger: create-tech-spec
workflow: "{project-root}/{bmad_folder}/bmm/workflows/bmad-quick-flow/create-tech-spec/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/bmad-quick-flow/create-tech-spec/workflow.yaml"
description: Architect a technical spec with implementation-ready stories description: Architect a technical spec with implementation-ready stories (Required first step)
- trigger: quick-dev - trigger: quick-dev
workflow: "{project-root}/{bmad_folder}/bmm/workflows/bmad-quick-flow/quick-dev/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/bmad-quick-flow/quick-dev/workflow.yaml"
description: Ship features from spec or direct instructions - no handoffs description: Implement the tech spec end-to-end solo (Core of Quick Flow)
- trigger: code-review - trigger: code-review
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/code-review/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/code-review/workflow.yaml"
description: Review code for quality, patterns, and acceptance criteria description: Review code and improve it (Highly Recommended, use fresh context and different LLM for best results)
- trigger: party-mode - trigger: party-mode
workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml" workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml"

View File

@ -26,24 +26,24 @@ agent:
menu: menu:
- trigger: sprint-planning - trigger: sprint-planning
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/sprint-planning/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/sprint-planning/workflow.yaml"
description: Generate or update sprint-status.yaml from epic files description: Generate or re-generate sprint-status.yaml from epic files (Required after Epics+Stories are created)
- trigger: create-story - trigger: create-story
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/create-story/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/create-story/workflow.yaml"
description: Create a Draft Story description: Create a Draft Story (Required to prepare stories for development)
- trigger: validate-create-story - trigger: validate-create-story
validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/create-story/workflow.yaml" validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/create-story/workflow.yaml"
description: (Optional) Validate Story Draft with Independent Review description: Validate Story Draft (Highly Recommended, use fresh context and different LLM for best results)
- trigger: epic-retrospective - trigger: epic-retrospective
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/retrospective/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/retrospective/workflow.yaml"
data: "{project-root}/{bmad_folder}/_cfg/agent-manifest.csv" data: "{project-root}/{bmad_folder}/_cfg/agent-manifest.csv"
description: (Optional) Facilitate team retrospective after an epic is completed description: Facilitate team retrospective after an epic is completed (Optional)
- trigger: correct-course - trigger: correct-course
workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/correct-course/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/correct-course/workflow.yaml"
description: (Optional) Execute correct-course task description: Execute correct-course task (When implementation is off-track)
- trigger: party-mode - trigger: party-mode
workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml" workflow: "{project-root}/{bmad_folder}/core/workflows/party-mode/workflow.yaml"

View File

@ -25,7 +25,7 @@ agent:
menu: menu:
- trigger: create-ux-design - trigger: create-ux-design
workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/create-ux-design/workflow.yaml" workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/create-ux-design/workflow.yaml"
description: Conduct Design Thinking Workshop to Define the User Specification with PRD as input description: Generate a UX Design and UI Plan from a PRD (Recommended before creating Architecture)
- trigger: validate-design - trigger: validate-design
validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/create-ux-design/workflow.yaml" validate-workflow: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/create-ux-design/workflow.yaml"

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -3,7 +3,7 @@
<critical>The workflow execution engine is governed by: {project-root}/{bmad_folder}/core/tasks/workflow.xml</critical> <critical>The workflow execution engine is governed by: {project-root}/{bmad_folder}/core/tasks/workflow.xml</critical>
<critical>You MUST have already loaded and processed: workflow-init/workflow.yaml</critical> <critical>You MUST have already loaded and processed: workflow-init/workflow.yaml</critical>
<critical>Communicate in {communication_language} with {user_name}</critical> <critical>Communicate in {communication_language} with {user_name}</critical>
<critical>This workflow handles BOTH new projects AND legacy projects being migrated to BMad Method</critical> <critical>This workflow handles BOTH new projects AND legacy projects following the BMad Method</critical>
<workflow> <workflow>
@ -12,7 +12,7 @@
<action>Perform comprehensive scan for existing work: <action>Perform comprehensive scan for existing work:
- BMM artifacts: PRD, tech-spec, epics, architecture, UX, brief, research, brainstorm - BMM artifacts: PRD, epics, architecture, UX, brief, research, brainstorm
- Implementation: stories, sprint-status, workflow-status - Implementation: stories, sprint-status, workflow-status
- Codebase: source directories, package files, git repo - Codebase: source directories, package files, git repo
- Check both {output_folder} and {sprint_artifacts} locations - Check both {output_folder} and {sprint_artifacts} locations
@ -53,31 +53,31 @@ Happy building! 🚀</output>
<ask>How would you like to proceed? <ask>How would you like to proceed?
a) **Continue** - Work with existing artifacts 1. **Continue** - Work with existing artifacts
b) **Archive & Start Fresh** - Move old work to archive 2. **Archive & Start Fresh** - Move old work to archive
c) **Express Setup** - I know exactly what I need 3. **Express Setup** - I know exactly what I need
d) **Guided Setup** - Walk me through options 4. **Guided Setup** - Walk me through options
Choice [a/b/c/d]:</ask> Choice [1-4]</ask>
<check if="choice == a"> <check if="choice == 1">
<action>Set continuing_existing = true</action> <action>Set continuing_existing = true</action>
<action>Store found artifacts</action> <action>Store found artifacts</action>
<action>Continue to step 7 (detect track from artifacts)</action> <action>Continue to step 7 (detect track from artifacts)</action>
</check> </check>
<check if="choice == b"> <check if="choice == 2">
<ask>Archive existing work? (y/n)</ask> <ask>Archive existing work? (y/n)</ask>
<action if="y">Move artifacts to {output_folder}/archive/</action> <action if="y">Move artifacts to {output_folder}/archive/</action>
<output>Ready for fresh start!</output> <output>Ready for fresh start!</output>
<action>Continue to step 3</action> <action>Continue to step 3</action>
</check> </check>
<check if="choice == c"> <check if="choice == 3">
<action>Jump to step 3 (express path)</action> <action>Jump to step 3 (express path)</action>
</check> </check>
<check if="choice == d"> <check if="choice == 4">
<action>Continue to step 4 (guided path)</action> <action>Continue to step 4 (guided path)</action>
</check> </check>
</check> </check>
@ -85,16 +85,16 @@ Choice [a/b/c/d]:</ask>
<check if="state == CLEAN"> <check if="state == CLEAN">
<ask>Setup approach: <ask>Setup approach:
a) **Express** - I know what I need 1. **Express** - I know what I need
b) **Guided** - Show me the options 2. **Guided** - Show me the options
Choice [a/b]:</ask> Choice [1 or 2]:</ask>
<check if="choice == a"> <check if="choice == 1">
<action>Continue to step 3 (express)</action> <action>Continue to step 3 (express)</action>
</check> </check>
<check if="choice == b"> <check if="choice == 2">
<action>Continue to step 4 (guided)</action> <action>Continue to step 4 (guided)</action>
</check> </check>
</check> </check>
@ -102,20 +102,22 @@ Choice [a/b]:</ask>
<step n="3" goal="Express setup path"> <step n="3" goal="Express setup path">
<ask>Is this for: <ask>Is this for:
1) **New project** (greenfield) 1. **New project** (greenfield)
2) **Existing codebase** (brownfield) 2. **Existing codebase** (brownfield)
Choice [1/2]:</ask> Choice [1/2]:</ask>
<action>Set field_type based on choice</action> <action>Set field_type based on choice</action>
<ask>Planning approach: <ask>Planning approach:
1. **Quick Flow** - Minimal planning, fast to code 1. **BMad Method** - Full planning for complex projects
2. **BMad Method** - Full planning for complex projects 2. **Enterprise Method** - Extended planning with security/DevOps
3. **Enterprise Method** - Extended planning with security/DevOps
Choice [1/2/3]:</ask> Choice [1/2]:</ask>
<action>Map to selected_track: quick-flow/method/enterprise</action> <action>Map to selected_track: method/enterprise</action>
<output>🚀 **For Quick Flow (minimal planning, straight to code):**
Load the **quick-flow-solo-dev** agent instead - use Quick Flow agent for faster development</output>
<template-output>field_type</template-output> <template-output>field_type</template-output>
<template-output>selected_track</template-output> <template-output>selected_track</template-output>
@ -135,8 +137,8 @@ Choice [1/2/3]:</ask>
<check if="field_type unclear AND codebase exists"> <check if="field_type unclear AND codebase exists">
<ask>I see existing code. Are you: <ask>I see existing code. Are you:
1) **Modifying** existing codebase (brownfield) 1. **Modifying** existing codebase (brownfield)
2) **Starting fresh** - code is just scaffold (greenfield) 2. **Starting fresh** - code is just scaffold (greenfield)
Choice [1/2]:</ask> Choice [1/2]:</ask>
<action>Set field_type based on answer</action> <action>Set field_type based on answer</action>
@ -165,44 +167,60 @@ Continue with software workflows? (y/n)</output>
</step> </step>
<step n="5" goal="Guided setup - select track"> <step n="5" goal="Guided setup - select track">
<output>Based on your project, here are your planning options: <output>Based on your project, here are your BMad Method planning options:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
**1. Quick Flow** 🚀 **1. BMad Method** 🎯 {{#if recommended}}(RECOMMENDED){{/if}}
- Minimal planning, straight to code
- Best for: Simple features, bug fixes
- Risk: Potential rework if complexity emerges
**2. BMad Method** 🎯 {{#if recommended}}(RECOMMENDED){{/if}}
- Full planning: PRD + UX + Architecture - Full planning: PRD + UX + Architecture
- Best for: Products, platforms, complex features - Best for: Products, platforms, complex features
- Benefit: AI agents have complete context for better results - Benefit: AI agents have complete context for better results
**3. Enterprise Method** 🏢 **2. Enterprise Method** 🏢
- Extended: Method + Security + DevOps + Testing - Extended: Method + Security + DevOps + Testing
- Best for: Enterprise, compliance, mission-critical - Best for: Enterprise, compliance, mission-critical
- Benefit: Comprehensive planning for complex systems - Benefit: Comprehensive planning for complex systems
**🚀 For Quick Flow (minimal planning, straight to code):**
Load the **quick-flow-solo-dev** agent instead - use Quick Flow agent for faster development
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{{#if brownfield}} {{#if brownfield}}
💡 Architecture creates focused solution design from your codebase, keeping AI agents on track. 💡 Architecture creates focused solution design from your codebase, keeping AI agents on track.
{{/if}}</output> {{/if}}</output>
<ask>Which approach fits best? <ask>Which BMad Method approach fits best?
1. Quick Flow 1. BMad Method {{#if recommended}}(recommended){{/if}}
2. BMad Method {{#if recommended}}(recommended){{/if}} 2. Enterprise Method
3. Enterprise Method 3. Help me decide
4. Help me decide 4. Switch to Quick Flow (use quick-flow-solo-dev agent)
Choice [1/2/3/4]:</ask> Choice [1/2/3/4]:</ask>
<check if="choice == 4"> <check if="choice == 4">
<output>🚀 **Switching to Quick Flow!**
Load the **quick-flow-solo-dev** agent instead:
- Start a new chat
- Load the quick-flow-solo-dev agent
- Use Quick Flow for minimal planning and faster development
Quick Flow is perfect for:
- Simple features and bug fixes
- Rapid prototyping
- When you want to get straight to code
Happy coding! 🚀</output>
<action>Exit workflow</action>
</check>
<check if="choice == 3">
<ask>What concerns you about choosing?</ask> <ask>What concerns you about choosing?</ask>
<action>Provide tailored guidance based on concerns</action> <action>Provide tailored guidance based on concerns</action>
<action>Loop back to choice</action> <action>Loop back to choice</action>
@ -215,7 +233,7 @@ Choice [1/2/3/4]:</ask>
<step n="6" goal="Discovery workflows selection (unified)"> <step n="6" goal="Discovery workflows selection (unified)">
<action>Determine available discovery workflows based on: <action>Determine available discovery workflows based on:
- field_type (greenfield gets product-brief option) - field_type (greenfield gets product-brief option)
- selected_track (quick-flow skips product-brief) - selected_track (method/enterprise options)
</action> </action>
<check if="field_type == greenfield AND selected_track in [method, enterprise]"> <check if="field_type == greenfield AND selected_track in [method, enterprise]">
@ -229,7 +247,7 @@ Choice [1/2/3/4]:</ask>
Enter numbers (e.g., "1,3" or "all" or "none"): </ask> Enter numbers (e.g., "1,3" or "all" or "none"): </ask>
</check> </check>
<check if="field_type == brownfield OR selected_track == quick-flow"> <check if="field_type == brownfield AND selected_track in [method, enterprise]">
<output>Optional discovery workflows:</output> <output>Optional discovery workflows:</output>
<ask>Include any of these? <ask>Include any of these?
@ -250,7 +268,7 @@ Enter numbers (e.g., "1,2" or "none"): </ask>
<template-output>research_requested</template-output> <template-output>research_requested</template-output>
<template-output>product_brief_requested</template-output> <template-output>product_brief_requested</template-output>
<check if="brownfield AND selected_track != quick-flow"> <check if="brownfield">
<output>💡 **Note:** For brownfield projects, run document-project workflow first to analyze your codebase.</output> <output>💡 **Note:** For brownfield projects, run document-project workflow first to analyze your codebase.</output>
</check> </check>
</step> </step>
@ -258,18 +276,18 @@ Enter numbers (e.g., "1,2" or "none"): </ask>
<step n="7" goal="Detect track from artifacts" if="continuing_existing OR migrating_legacy"> <step n="7" goal="Detect track from artifacts" if="continuing_existing OR migrating_legacy">
<action>Analyze artifacts to detect track: <action>Analyze artifacts to detect track:
- Has PRD → BMad Method - Has PRD → BMad Method
- Has tech-spec only → Quick Flow
- Has Security/DevOps → Enterprise Method - Has Security/DevOps → Enterprise Method
- Has tech-spec only → Suggest switching to quick-flow-solo-dev agent
</action> </action>
<output>Detected: **{{detected_track}}** based on {{found_artifacts}}</output> <output>Detected: **{{detected_track}}** based on {{found_artifacts}}</output>
<ask>Correct? (y/n)</ask> <ask>Correct? (y/n)</ask>
<ask if="n">Which track instead? <ask if="n">Which BMad Method track instead?
1. Quick Flow 1. BMad Method
2. BMad Method 2. Enterprise Method
3. Enterprise Method 3. Switch to Quick Flow (use quick-flow-solo-dev agent)
Choice:</ask> Choice:</ask>
@ -298,11 +316,8 @@ Choice:</ask>
{{#if brownfield}}Prerequisites: document-project{{/if}} {{#if brownfield}}Prerequisites: document-project{{/if}}
{{#if has_discovery}}Discovery: {{list_selected_discovery}}{{/if}} {{#if has_discovery}}Discovery: {{list_selected_discovery}}{{/if}}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{{workflow_path_summary}} {{workflow_path_summary}}
</output>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</output>
<ask>Create workflow tracking file? (y/n)</ask> <ask>Create workflow tracking file? (y/n)</ask>
@ -326,9 +341,6 @@ To check progress: /bmad:bmm:workflows:workflow-status
Happy building! 🚀</output> Happy building! 🚀</output>
</check> </check>
<check if="n">
<output>No problem! Run workflow-init again when ready.</output>
</check>
</step> </step>
</workflow> </workflow>

View File

@ -37,12 +37,19 @@
<action>Search {output_folder}/ for file: bmm-workflow-status.yaml</action> <action>Search {output_folder}/ for file: bmm-workflow-status.yaml</action>
<check if="no status file found"> <check if="no status file found">
<output>No workflow status found. To get started: <output>No workflow status found.</output>
<ask>Would you like to run Workflow Init now? (y/n)</ask>
Load analyst agent and run: `workflow-init` <check if="response == y OR response == yes">
<action>Launching workflow-init to set up your project tracking...</action>
<invoke-workflow path="{project-root}/{bmad_folder}/bmm/workflows/workflow-status/init/workflow.yaml"></invoke-workflow>
<action>Exit workflow and let workflow-init take over</action>
</check>
This will guide you through project setup and create your workflow path.</output> <check if="else">
<action>Exit workflow</action> <output>No workflow status file. Run workflow-init when ready to enable progress tracking.</output>
<action>Exit workflow</action>
</check>
</check> </check>
<check if="status file found"> <check if="status file found">

View File

@ -1,67 +0,0 @@
# BMad Quick Flow - Brownfield
# Fast spec-driven development for existing codebases (1-10 stories typically)
method_name: "BMad Quick Flow"
track: "quick-flow"
field_type: "brownfield"
description: "Spec-driven development for brownfield projects - streamlined path with codebase context"
phases:
- prerequisite: true
name: "Documentation"
conditional: "if_undocumented"
note: "NOT a phase - prerequisite for brownfield without docs"
workflows:
- id: "document-project"
required: true
agent: "analyst"
command: "document-project"
output: "Comprehensive project documentation"
purpose: "Generate codebase context for spec engineering"
- phase: 0
name: "Discovery (Optional)"
optional: true
note: "User-selected during workflow-init"
workflows:
- id: "brainstorm-project"
optional: true
agent: "analyst"
command: "brainstorm-project"
included_by: "user_choice"
- id: "research"
optional: true
agent: "analyst"
command: "research"
included_by: "user_choice"
- phase: 1
name: "Spec Engineering"
required: true
workflows:
- id: "create-tech-spec"
required: true
agent: "quick-flow-solo-dev"
command: "create-tech-spec"
output: "Technical Specification with implementation-ready stories"
note: "Stories include codebase context from document-project"
- phase: 2
name: "Implementation"
required: true
note: "Barry executes all stories, optional code-review after each"
workflows:
- id: "dev-spec"
required: true
repeat: true
agent: "quick-flow-solo-dev"
command: "dev-spec"
note: "Execute stories from spec - Barry is the one-man powerhouse"
- id: "code-review"
optional: true
repeat: true
agent: "quick-flow-solo-dev"
command: "code-review"
note: "Review completed story implementation"

View File

@ -1,56 +0,0 @@
# BMad Quick Flow - Greenfield
# Fast spec-driven development path (1-10 stories typically)
method_name: "BMad Quick Flow"
track: "quick-flow"
field_type: "greenfield"
description: "Spec-driven development for greenfield projects - streamlined path without sprint overhead"
phases:
- phase: 0
name: "Discovery (Optional)"
optional: true
note: "User-selected during workflow-init"
workflows:
- id: "brainstorm-project"
optional: true
agent: "analyst"
command: "brainstorm-project"
included_by: "user_choice"
- id: "research"
optional: true
agent: "analyst"
command: "research"
included_by: "user_choice"
note: "Can have multiple research workflows"
- phase: 1
name: "Spec Engineering"
required: true
workflows:
- id: "create-tech-spec"
required: true
agent: "quick-flow-solo-dev"
command: "create-tech-spec"
output: "Technical Specification with implementation-ready stories"
note: "Stories contain all context for execution"
- phase: 2
name: "Implementation"
required: true
note: "Barry executes all stories, optional code-review after each"
workflows:
- id: "dev-spec"
required: true
repeat: true
agent: "quick-flow-solo-dev"
command: "dev-spec"
note: "Execute stories from spec - Barry is the one-man powerhouse"
- id: "code-review"
optional: true
repeat: true
agent: "quick-flow-solo-dev"
command: "code-review"
note: "Review completed story implementation"

View File

@ -1,5 +1,6 @@
<rules> <rules>
- ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style - ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style
<!-- TTS_INJECTION:agent-tts -->
- Stay in character until exit selected - Stay in character until exit selected
- Menu triggers use asterisk (*) - NOT markdown, display exactly as shown - Menu triggers use asterisk (*) - NOT markdown, display exactly as shown
- Number all lists, use letters for sub-options - Number all lists, use letters for sub-options

381
test-bmad-pr.sh Executable file
View File

@ -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 ""

View File

@ -162,6 +162,7 @@ The installer supports **15 IDE environments** through a base-derived architectu
| `gemini` | Google Gemini | `.gemini/` | | `gemini` | Google Gemini | `.gemini/` |
| `qwen` | Qwen | `.qwen/` | | `qwen` | Qwen | `.qwen/` |
| `roo` | Roo | `.roo/` | | `roo` | Roo | `.roo/` |
| `rovo-dev` | Rovo | `.rovodev/` |
| `trae` | Trae | `.trae/` | | `trae` | Trae | `.trae/` |
| `iflow` | iFlow | `.iflow/` | | `iflow` | iFlow | `.iflow/` |
| `kilo` | Kilo | `.kilo/` | | `kilo` | Kilo | `.kilo/` |

View File

@ -0,0 +1,141 @@
const chalk = require('chalk');
const nodePath = require('node:path');
const { Installer } = require('../installers/lib/core/installer');
module.exports = {
command: 'cleanup',
description: 'Clean up obsolete files from BMAD installation',
options: [
['-d, --dry-run', 'Show what would be deleted without actually deleting'],
['-a, --auto-delete', 'Automatically delete non-retained files without prompts'],
['-l, --list-retained', 'List currently retained files'],
['-c, --clear-retained', 'Clear retained files list'],
],
action: async (options) => {
try {
// Create installer and let it find the BMAD directory
const installer = new Installer();
const bmadDir = await installer.findBmadDir(process.cwd());
if (!bmadDir) {
console.error(chalk.red('❌ BMAD installation not found'));
process.exit(1);
}
const retentionPath = nodePath.join(bmadDir, '_cfg', 'user-retained-files.yaml');
// Handle list-retained option
if (options.listRetained) {
const fs = require('fs-extra');
const yaml = require('js-yaml');
if (await fs.pathExists(retentionPath)) {
const retentionContent = await fs.readFile(retentionPath, 'utf8');
const retentionData = yaml.load(retentionContent) || { retainedFiles: [] };
if (retentionData.retainedFiles.length > 0) {
console.log(chalk.cyan('\n📋 Retained Files:\n'));
for (const file of retentionData.retainedFiles) {
console.log(chalk.dim(` - ${file}`));
}
console.log();
} else {
console.log(chalk.yellow('\n✨ No retained files found\n'));
}
} else {
console.log(chalk.yellow('\n✨ No retained files found\n'));
}
return;
}
// Handle clear-retained option
if (options.clearRetained) {
const fs = require('fs-extra');
if (await fs.pathExists(retentionPath)) {
await fs.remove(retentionPath);
console.log(chalk.green('\n✅ Cleared retained files list\n'));
} else {
console.log(chalk.yellow('\n✨ No retained files list to clear\n'));
}
return;
}
// Handle cleanup operations
if (options.dryRun) {
console.log(chalk.cyan('\n🔍 Legacy File Scan (Dry Run)\n'));
const legacyFiles = await installer.scanForLegacyFiles(bmadDir);
const allLegacyFiles = [
...legacyFiles.backup,
...legacyFiles.documentation,
...legacyFiles.deprecated_task,
...legacyFiles.unknown,
];
if (allLegacyFiles.length === 0) {
console.log(chalk.green('✨ No legacy files found\n'));
return;
}
// Group files by category
const categories = [];
if (legacyFiles.backup.length > 0) {
categories.push({ name: 'Backup Files (.bak)', files: legacyFiles.backup });
}
if (legacyFiles.documentation.length > 0) {
categories.push({ name: 'Documentation', files: legacyFiles.documentation });
}
if (legacyFiles.deprecated_task.length > 0) {
categories.push({ name: 'Deprecated Task Files', files: legacyFiles.deprecated_task });
}
if (legacyFiles.unknown.length > 0) {
categories.push({ name: 'Unknown Files', files: legacyFiles.unknown });
}
for (const category of categories) {
console.log(chalk.yellow(`${category.name}:`));
for (const file of category.files) {
const size = (file.size / 1024).toFixed(1);
const date = file.mtime.toLocaleDateString();
let line = ` - ${file.relativePath} (${size}KB, ${date})`;
if (file.suggestedAlternative) {
line += chalk.dim(`${file.suggestedAlternative}`);
}
console.log(chalk.dim(line));
}
console.log();
}
console.log(chalk.cyan(`Found ${allLegacyFiles.length} legacy file(s) that could be cleaned up.\n`));
console.log(chalk.dim('Run "bmad cleanup" to actually delete these files.\n'));
return;
}
// Perform actual cleanup
console.log(chalk.cyan('\n🧹 Cleaning up legacy files...\n'));
const result = await installer.performCleanup(bmadDir, options.autoDelete);
if (result.message) {
console.log(chalk.dim(result.message));
} else {
if (result.deleted > 0) {
console.log(chalk.green(`✅ Deleted ${result.deleted} legacy file(s)`));
}
if (result.retained > 0) {
console.log(chalk.yellow(`⏭️ Retained ${result.retained} file(s)`));
console.log(chalk.dim('Run "bmad cleanup --list-retained" to see retained files\n'));
}
}
console.log();
} catch (error) {
console.error(chalk.red(`❌ Error: ${error.message}`));
process.exit(1);
}
},
};

View File

@ -11,8 +11,8 @@ const kiroGenerator = new KiroCLIGenerator();
module.exports = { module.exports = {
command: 'install', command: 'install',
description: 'Install BMAD Core agents and tools', description: 'Install BMAD Core agents and tools',
options: [], options: [['--skip-cleanup', 'Skip automatic cleanup of legacy files']],
action: async () => { action: async (options) => {
try { try {
const config = await ui.promptInstall(); const config = await ui.promptInstall();
@ -46,6 +46,11 @@ module.exports = {
config._requestedReinstall = true; config._requestedReinstall = true;
} }
// Add skip cleanup flag if option provided
if (options && options.skipCleanup) {
config.skipCleanup = true;
}
// Regular install/update flow // Regular install/update flow
const result = await installer.install(config); const result = await installer.install(config);
@ -71,6 +76,46 @@ module.exports = {
console.log(chalk.yellow('\nThank you for helping test the early release version of the new BMad Core and BMad Method!')); 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!')); 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); process.exit(0);
} }
} catch (error) { } catch (error) {

View File

@ -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 path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const chalk = require('chalk'); const chalk = require('chalk');
@ -69,10 +89,41 @@ class Installer {
} }
/** /**
* Copy a file and replace {bmad_folder} placeholder with actual folder name * @function copyFileWithPlaceholderReplacement
* @param {string} sourcePath - Source file path * @intent Copy files from BMAD source to installation directory with dynamic content transformation
* @param {string} targetPath - Target file path * @why Enables installation-time customization: {bmad_folder} replacement + optional AgentVibes TTS injection
* @param {string} bmadFolderName - The bmad folder name to use for replacement * @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) { async copyFileWithPlaceholderReplacement(sourcePath, targetPath, bmadFolderName) {
// List of text file extensions that should have placeholder replacement // List of text file extensions that should have placeholder replacement
@ -90,6 +141,9 @@ class Installer {
content = content.replaceAll('{bmad_folder}', bmadFolderName); content = content.replaceAll('{bmad_folder}', bmadFolderName);
} }
// Process AgentVibes injection points
content = this.processTTSInjectionPoints(content);
// 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');
@ -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 * Collect Tool/IDE configurations after module configuration
* @param {string} projectDir - Project directory * @param {string} projectDir - Project directory
@ -166,7 +320,9 @@ class Installer {
for (const ide of newlySelectedIdes) { for (const ide of newlySelectedIdes) {
// List of IDEs that have interactive prompts // List of IDEs that have interactive prompts
const needsPrompts = ['claude-code', 'github-copilot', 'roo', 'cline', 'auggie', 'codex', 'qwen', 'gemini'].includes(ide); const needsPrompts = ['claude-code', 'github-copilot', 'roo', 'cline', 'auggie', 'codex', 'qwen', 'gemini', 'rovo-dev'].includes(
ide,
);
if (needsPrompts) { if (needsPrompts) {
// Get IDE handler and collect configuration // Get IDE handler and collect configuration
@ -269,6 +425,9 @@ class Installer {
const bmadFolderName = moduleConfigs.core && moduleConfigs.core.bmad_folder ? moduleConfigs.core.bmad_folder : 'bmad'; const bmadFolderName = moduleConfigs.core && moduleConfigs.core.bmad_folder ? moduleConfigs.core.bmad_folder : 'bmad';
this.bmadFolderName = bmadFolderName; // Store for use in other methods 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 // Set bmad folder name on module manager and IDE manager for placeholder replacement
this.moduleManager.setBmadFolderName(bmadFolderName); this.moduleManager.setBmadFolderName(bmadFolderName);
this.ideManager.setBmadFolderName(bmadFolderName); this.ideManager.setBmadFolderName(bmadFolderName);
@ -859,7 +1018,31 @@ class Installer {
customFiles: customFiles.length > 0 ? customFiles : undefined, customFiles: customFiles.length > 0 ? customFiles : undefined,
}); });
return { success: true, path: bmadDir, modules: config.modules, ides: config.ides }; // Offer cleanup for legacy files (only for updates, not fresh installs, and only if not skipped)
if (!config.skipCleanup && config._isUpdate) {
try {
const cleanupResult = await this.performCleanup(bmadDir, false);
if (cleanupResult.deleted > 0) {
console.log(chalk.green(`\n✓ Cleaned up ${cleanupResult.deleted} legacy file${cleanupResult.deleted > 1 ? 's' : ''}`));
}
if (cleanupResult.retained > 0) {
console.log(chalk.dim(`Run 'bmad cleanup' anytime to manage retained files`));
}
} catch (cleanupError) {
// Don't fail the installation for cleanup errors
console.log(chalk.yellow(`\n⚠️ Cleanup warning: ${cleanupError.message}`));
console.log(chalk.dim('Run "bmad cleanup" to manually clean up legacy files'));
}
}
return {
success: true,
path: bmadDir,
modules: config.modules,
ides: config.ides,
needsAgentVibes: this.enableAgentVibes && !config.agentVibesInstalled,
projectDir: projectDir,
};
} catch (error) { } catch (error) {
spinner.fail('Installation failed'); spinner.fail('Installation failed');
throw error; throw error;
@ -1773,7 +1956,7 @@ class Installer {
if (existingBmadFolderName === newBmadFolderName) { if (existingBmadFolderName === newBmadFolderName) {
// Normal quick update - start the spinner // Normal quick update - start the spinner
spinner.start('Updating BMAD installation...'); console.log(chalk.cyan('Updating BMAD installation...'));
} else { } else {
// Folder name has changed - stop spinner and let install() handle it // Folder name has changed - stop spinner and let install() handle it
spinner.stop(); spinner.stop();
@ -2412,6 +2595,362 @@ class Installer {
} }
} }
} }
/**
* Scan for legacy/obsolete files in BMAD installation
* @param {string} bmadDir - BMAD installation directory
* @returns {Object} Categorized files for cleanup
*/
async scanForLegacyFiles(bmadDir) {
const legacyFiles = {
backup: [],
documentation: [],
deprecated_task: [],
unknown: [],
};
try {
// Load files manifest to understand what should exist
const manifestPath = path.join(bmadDir, 'files-manifest.csv');
const manifestFiles = new Set();
if (await fs.pathExists(manifestPath)) {
const manifestContent = await fs.readFile(manifestPath, 'utf8');
const lines = manifestContent.split('\n').slice(1); // Skip header
for (const line of lines) {
if (line.trim()) {
const relativePath = line.split(',')[0];
if (relativePath) {
manifestFiles.add(relativePath);
}
}
}
}
// Scan all files recursively
const allFiles = await this.getAllFiles(bmadDir);
for (const filePath of allFiles) {
const relativePath = path.relative(bmadDir, filePath);
// Skip expected files
if (this.isExpectedFile(relativePath, manifestFiles)) {
continue;
}
// Categorize legacy files
if (relativePath.endsWith('.bak')) {
legacyFiles.backup.push({
path: filePath,
relativePath: relativePath,
size: (await fs.stat(filePath)).size,
mtime: (await fs.stat(filePath)).mtime,
});
} else if (this.isDocumentationFile(relativePath)) {
legacyFiles.documentation.push({
path: filePath,
relativePath: relativePath,
size: (await fs.stat(filePath)).size,
mtime: (await fs.stat(filePath)).mtime,
});
} else if (this.isDeprecatedTaskFile(relativePath)) {
const suggestedAlternative = this.suggestAlternative(relativePath);
legacyFiles.deprecated_task.push({
path: filePath,
relativePath: relativePath,
size: (await fs.stat(filePath)).size,
mtime: (await fs.stat(filePath)).mtime,
suggestedAlternative,
});
} else {
legacyFiles.unknown.push({
path: filePath,
relativePath: relativePath,
size: (await fs.stat(filePath)).size,
mtime: (await fs.stat(filePath)).mtime,
});
}
}
} catch (error) {
console.warn(`Warning: Could not scan for legacy files: ${error.message}`);
}
return legacyFiles;
}
/**
* Get all files in directory recursively
* @param {string} dir - Directory to scan
* @returns {Array} Array of file paths
*/
async getAllFiles(dir) {
const files = [];
async function scan(currentDir) {
const entries = await fs.readdir(currentDir);
for (const entry of entries) {
const fullPath = path.join(currentDir, entry);
const stat = await fs.stat(fullPath);
if (stat.isDirectory()) {
// Skip certain directories
if (!['node_modules', '.git', 'dist', 'build'].includes(entry)) {
await scan(fullPath);
}
} else {
files.push(fullPath);
}
}
}
await scan(dir);
return files;
}
/**
* Check if file is expected in installation
* @param {string} relativePath - Relative path from BMAD dir
* @param {Set} manifestFiles - Files from manifest
* @returns {boolean} True if expected file
*/
isExpectedFile(relativePath, manifestFiles) {
// Core files in manifest
if (manifestFiles.has(relativePath)) {
return true;
}
// Configuration files
if (relativePath.startsWith('_cfg/') || relativePath === 'config.yaml') {
return true;
}
// Custom files
if (relativePath.startsWith('custom/') || relativePath === 'manifest.yaml') {
return true;
}
// Generated files
if (relativePath === 'manifest.csv' || relativePath === 'files-manifest.csv') {
return true;
}
// IDE-specific files
const ides = ['vscode', 'cursor', 'windsurf', 'claude-code', 'github-copilot', 'zsh', 'bash', 'fish'];
if (ides.some((ide) => relativePath.includes(ide))) {
return true;
}
// BMAD MODULE STRUCTURES - recognize valid module content
const modulePrefixes = ['bmb/', 'bmm/', 'cis/', 'core/', 'bmgd/'];
const validExtensions = ['.yaml', '.yml', '.json', '.csv', '.md', '.xml', '.svg', '.png', '.jpg', '.gif', '.excalidraw', '.js'];
// Check if this file is in a recognized module directory
for (const modulePrefix of modulePrefixes) {
if (relativePath.startsWith(modulePrefix)) {
// Check if it has a valid extension
const hasValidExtension = validExtensions.some((ext) => relativePath.endsWith(ext));
if (hasValidExtension) {
return true;
}
}
}
// Special case for core module resources
if (relativePath.startsWith('core/resources/')) {
return true;
}
// Special case for docs directory
if (relativePath.startsWith('docs/')) {
return true;
}
return false;
}
/**
* Check if file is documentation
* @param {string} relativePath - Relative path
* @returns {boolean} True if documentation
*/
isDocumentationFile(relativePath) {
const docExtensions = ['.md', '.txt', '.pdf'];
const docPatterns = ['docs/', 'README', 'CHANGELOG', 'LICENSE'];
return docExtensions.some((ext) => relativePath.endsWith(ext)) || docPatterns.some((pattern) => relativePath.includes(pattern));
}
/**
* Check if file is deprecated task file
* @param {string} relativePath - Relative path
* @returns {boolean} True if deprecated
*/
isDeprecatedTaskFile(relativePath) {
// Known deprecated files
const deprecatedFiles = ['adv-elicit-methods.csv', 'game-resources.json', 'ux-workflow.json'];
return deprecatedFiles.some((dep) => relativePath.includes(dep));
}
/**
* Suggest alternative for deprecated file
* @param {string} relativePath - Deprecated file path
* @returns {string} Suggested alternative
*/
suggestAlternative(relativePath) {
const alternatives = {
'adv-elicit-methods.csv': 'Use the new structured workflows in src/modules/',
'game-resources.json': 'Resources are now integrated into modules',
'ux-workflow.json': 'UX workflows are now in src/modules/bmm/workflows/',
};
for (const [deprecated, alternative] of Object.entries(alternatives)) {
if (relativePath.includes(deprecated)) {
return alternative;
}
}
return 'Check src/modules/ for new alternatives';
}
/**
* Perform interactive cleanup of legacy files
* @param {string} bmadDir - BMAD installation directory
* @param {boolean} skipInteractive - Skip interactive prompts
* @returns {Object} Cleanup results
*/
async performCleanup(bmadDir, skipInteractive = false) {
const inquirer = require('inquirer');
const yaml = require('js-yaml');
// Load user retention preferences
const retentionPath = path.join(bmadDir, '_cfg', 'user-retained-files.yaml');
let retentionData = { retainedFiles: [], history: [] };
if (await fs.pathExists(retentionPath)) {
const retentionContent = await fs.readFile(retentionPath, 'utf8');
retentionData = yaml.load(retentionContent) || retentionData;
}
// Scan for legacy files
const legacyFiles = await this.scanForLegacyFiles(bmadDir);
const allLegacyFiles = [...legacyFiles.backup, ...legacyFiles.documentation, ...legacyFiles.deprecated_task, ...legacyFiles.unknown];
if (allLegacyFiles.length === 0) {
return { deleted: 0, retained: 0, message: 'No legacy files found' };
}
let deletedCount = 0;
let retainedCount = 0;
const filesToDelete = [];
if (skipInteractive) {
// Auto-delete all non-retained files
for (const file of allLegacyFiles) {
if (!retentionData.retainedFiles.includes(file.relativePath)) {
filesToDelete.push(file);
}
}
} else {
// Interactive cleanup
console.log(chalk.cyan('\n🧹 Legacy File Cleanup\n'));
console.log(chalk.dim('The following obsolete files were found:\n'));
// Group files by category
const categories = [];
if (legacyFiles.backup.length > 0) {
categories.push({ name: 'Backup Files (.bak)', files: legacyFiles.backup });
}
if (legacyFiles.documentation.length > 0) {
categories.push({ name: 'Documentation', files: legacyFiles.documentation });
}
if (legacyFiles.deprecated_task.length > 0) {
categories.push({ name: 'Deprecated Task Files', files: legacyFiles.deprecated_task });
}
if (legacyFiles.unknown.length > 0) {
categories.push({ name: 'Unknown Files', files: legacyFiles.unknown });
}
for (const category of categories) {
console.log(chalk.yellow(`${category.name}:`));
for (const file of category.files) {
const size = (file.size / 1024).toFixed(1);
const date = file.mtime.toLocaleDateString();
let line = ` - ${file.relativePath} (${size}KB, ${date})`;
if (file.suggestedAlternative) {
line += chalk.dim(`${file.suggestedAlternative}`);
}
console.log(chalk.dim(line));
}
console.log();
}
const prompt = await inquirer.prompt([
{
type: 'confirm',
name: 'proceed',
message: 'Would you like to review these files for cleanup?',
default: true,
},
]);
if (!prompt.proceed) {
return { deleted: 0, retained: allLegacyFiles.length, message: 'Cleanup cancelled by user' };
}
// Show selection interface
const selectionPrompt = await inquirer.prompt([
{
type: 'checkbox',
name: 'filesToDelete',
message: 'Select files to delete (use SPACEBAR to select, ENTER to continue):',
choices: allLegacyFiles.map((file) => {
const isRetained = retentionData.retainedFiles.includes(file.relativePath);
const description = `${file.relativePath} (${(file.size / 1024).toFixed(1)}KB)`;
return {
name: description,
value: file,
checked: !isRetained && !file.relativePath.includes('.bak'),
};
}),
pageSize: Math.min(allLegacyFiles.length, 15),
},
]);
filesToDelete.push(...selectionPrompt.filesToDelete);
}
// Delete selected files
for (const file of filesToDelete) {
try {
await fs.remove(file.path);
deletedCount++;
} catch (error) {
console.warn(`Warning: Could not delete ${file.relativePath}: ${error.message}`);
}
}
// Count retained files
retainedCount = allLegacyFiles.length - deletedCount;
// Update retention data
const newlyRetained = allLegacyFiles.filter((f) => !filesToDelete.includes(f)).map((f) => f.relativePath);
retentionData.retainedFiles = [...new Set([...retentionData.retainedFiles, ...newlyRetained])];
retentionData.history.push({
date: new Date().toISOString(),
deleted: deletedCount,
retained: retainedCount,
files: filesToDelete.map((f) => f.relativePath),
});
// Save retention data
await fs.ensureDir(path.dirname(retentionPath));
await fs.writeFile(retentionPath, yaml.dump(retentionData), 'utf8');
return { deleted: deletedCount, retained: retainedCount };
}
} }
module.exports = { Installer }; module.exports = { Installer };

View File

@ -6,13 +6,13 @@ const { AgentCommandGenerator } = require('./shared/agent-command-generator');
/** /**
* GitHub Copilot setup handler * GitHub Copilot setup handler
* Creates chat modes in .github/chatmodes/ and configures VS Code settings * Creates agents in .github/agents/ and configures VS Code settings
*/ */
class GitHubCopilotSetup extends BaseIdeSetup { class GitHubCopilotSetup extends BaseIdeSetup {
constructor() { constructor() {
super('github-copilot', 'GitHub Copilot', true); // preferred IDE super('github-copilot', 'GitHub Copilot', true); // preferred IDE
this.configDir = '.github'; this.configDir = '.github';
this.chatmodesDir = 'chatmodes'; this.agentsDir = 'agents';
this.vscodeDir = '.vscode'; this.vscodeDir = '.vscode';
} }
@ -50,7 +50,8 @@ class GitHubCopilotSetup extends BaseIdeSetup {
message: 'Maximum requests per session (1-50)?', message: 'Maximum requests per session (1-50)?',
default: '15', default: '15',
validate: (input) => { validate: (input) => {
const num = parseInt(input); const num = parseInt(input, 10);
if (isNaN(num)) return 'Enter a valid number 1-50';
return (num >= 1 && num <= 50) || 'Enter 1-50'; return (num >= 1 && num <= 50) || 'Enter 1-50';
}, },
}, },
@ -97,10 +98,10 @@ class GitHubCopilotSetup extends BaseIdeSetup {
const config = options.preCollectedConfig || {}; const config = options.preCollectedConfig || {};
await this.configureVsCodeSettings(projectDir, { ...options, ...config }); await this.configureVsCodeSettings(projectDir, { ...options, ...config });
// Create .github/chatmodes directory // Create .github/agents directory
const githubDir = path.join(projectDir, this.configDir); const githubDir = path.join(projectDir, this.configDir);
const chatmodesDir = path.join(githubDir, this.chatmodesDir); const agentsDir = path.join(githubDir, this.agentsDir);
await this.ensureDir(chatmodesDir); await this.ensureDir(agentsDir);
// Clean up any existing BMAD files before reinstalling // Clean up any existing BMAD files before reinstalling
await this.cleanup(projectDir); await this.cleanup(projectDir);
@ -109,29 +110,29 @@ class GitHubCopilotSetup extends BaseIdeSetup {
const agentGen = new AgentCommandGenerator(this.bmadFolderName); const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []); const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Create chat mode files with bmad- prefix // Create agent files with bmd- prefix
let modeCount = 0; let agentCount = 0;
for (const artifact of agentArtifacts) { for (const artifact of agentArtifacts) {
const content = artifact.content; const content = artifact.content;
const chatmodeContent = await this.createChatmodeContent({ module: artifact.module, name: artifact.name }, content); const agentContent = await this.createAgentContent({ module: artifact.module, name: artifact.name }, content);
// Use bmad- prefix: bmad-agent-{module}-{name}.chatmode.md // Use bmd- prefix: bmd-custom-{module}-{name}.agent.md
const targetPath = path.join(chatmodesDir, `bmad-agent-${artifact.module}-${artifact.name}.chatmode.md`); const targetPath = path.join(agentsDir, `bmd-custom-${artifact.module}-${artifact.name}.agent.md`);
await this.writeFile(targetPath, chatmodeContent); await this.writeFile(targetPath, agentContent);
modeCount++; agentCount++;
console.log(chalk.green(` ✓ Created chat mode: bmad-agent-${artifact.module}-${artifact.name}`)); console.log(chalk.green(` ✓ Created agent: bmd-custom-${artifact.module}-${artifact.name}`));
} }
console.log(chalk.green(`${this.name} configured:`)); console.log(chalk.green(`${this.name} configured:`));
console.log(chalk.dim(` - ${modeCount} chat modes created`)); console.log(chalk.dim(` - ${agentCount} agents created`));
console.log(chalk.dim(` - Chat modes directory: ${path.relative(projectDir, chatmodesDir)}`)); console.log(chalk.dim(` - Agents directory: ${path.relative(projectDir, agentsDir)}`));
console.log(chalk.dim(` - VS Code settings configured`)); console.log(chalk.dim(` - VS Code settings configured`));
console.log(chalk.dim('\n Chat modes available in VS Code Chat view')); console.log(chalk.dim('\n Agents available in VS Code Chat view'));
return { return {
success: true, success: true,
chatmodes: modeCount, agents: agentCount,
settings: true, settings: true,
}; };
} }
@ -187,9 +188,10 @@ class GitHubCopilotSetup extends BaseIdeSetup {
// Manual configuration - use pre-collected settings // Manual configuration - use pre-collected settings
const manual = options.manualSettings || {}; const manual = options.manualSettings || {};
const maxRequests = parseInt(manual.maxRequests || '15', 10);
bmadSettings = { bmadSettings = {
'chat.agent.enabled': true, 'chat.agent.enabled': true,
'chat.agent.maxRequests': parseInt(manual.maxRequests || 15), 'chat.agent.maxRequests': isNaN(maxRequests) ? 15 : maxRequests,
'github.copilot.chat.agent.runTasks': manual.runTasks === undefined ? true : manual.runTasks, 'github.copilot.chat.agent.runTasks': manual.runTasks === undefined ? true : manual.runTasks,
'chat.mcp.discovery.enabled': manual.mcpDiscovery === undefined ? true : manual.mcpDiscovery, 'chat.mcp.discovery.enabled': manual.mcpDiscovery === undefined ? true : manual.mcpDiscovery,
'github.copilot.chat.agent.autoFix': manual.autoFix === undefined ? true : manual.autoFix, 'github.copilot.chat.agent.autoFix': manual.autoFix === undefined ? true : manual.autoFix,
@ -206,9 +208,9 @@ class GitHubCopilotSetup extends BaseIdeSetup {
} }
/** /**
* Create chat mode content * Create agent content
*/ */
async createChatmodeContent(agent, content) { async createAgentContent(agent, content) {
// Extract metadata from launcher frontmatter if present // Extract metadata from launcher frontmatter if present
const descMatch = content.match(/description:\s*"([^"]+)"/); const descMatch = content.match(/description:\s*"([^"]+)"/);
const title = descMatch ? descMatch[1] : this.formatTitle(agent.name); const title = descMatch ? descMatch[1] : this.formatTitle(agent.name);
@ -226,30 +228,21 @@ class GitHubCopilotSetup extends BaseIdeSetup {
// Reference: https://code.visualstudio.com/docs/copilot/reference/copilot-vscode-features#_chat-tools // Reference: https://code.visualstudio.com/docs/copilot/reference/copilot-vscode-features#_chat-tools
const tools = [ const tools = [
'changes', // List of source control changes 'changes', // List of source control changes
'codebase', // Perform code search in workspace 'edit', // Edit files in your workspace including: createFile, createDirectory, editNotebook, newJupyterNotebook and editFiles
'createDirectory', // Create new directory in workspace
'createFile', // Create new file in workspace
'editFiles', // Apply edits to files in workspace
'fetch', // Fetch content from web page 'fetch', // Fetch content from web page
'fileSearch', // Search files using glob patterns
'githubRepo', // Perform code search in GitHub repo 'githubRepo', // Perform code search in GitHub repo
'listDirectory', // List files in a directory
'problems', // Add workspace issues from Problems panel 'problems', // Add workspace issues from Problems panel
'readFile', // Read content of a file in workspace 'runCommands', // Runs commands in the terminal including: getTerminalOutput, terminalSelection, terminalLastCommand and runInTerminal
'runInTerminal', // Run shell command in integrated terminal 'runTasks', // Runs tasks and gets their output for your workspace
'runTask', // Run existing task in workspace
'runTests', // Run unit tests in workspace 'runTests', // Run unit tests in workspace
'runVscodeCommand', // Run VS Code command 'search', // Search and read files in your workspace, including:fileSearch, textSearch, listDirectory, readFile, codebase and searchResults
'search', // Enable file searching in workspace 'runSubagent', // Runs a task within an isolated subagent context. Enables efficient organization of tasks and context window management.
'searchResults', // Get search results from Search view
'terminalLastCommand', // Get last terminal command and output
'terminalSelection', // Get current terminal selection
'testFailure', // Get unit test failure information 'testFailure', // Get unit test failure information
'textSearch', // Find text in files 'todos', // Tool for managing and tracking todo items for task planning
'usages', // Find references and navigate definitions 'usages', // Find references and navigate definitions
]; ];
let chatmodeContent = `--- let agentContent = `---
description: "${description.replaceAll('"', String.raw`\"`)}" description: "${description.replaceAll('"', String.raw`\"`)}"
tools: ${JSON.stringify(tools)} tools: ${JSON.stringify(tools)}
--- ---
@ -260,7 +253,7 @@ ${cleanContent}
`; `;
return chatmodeContent; return agentContent;
} }
/** /**
@ -278,10 +271,10 @@ ${cleanContent}
*/ */
async cleanup(projectDir) { async cleanup(projectDir) {
const fs = require('fs-extra'); const fs = require('fs-extra');
const chatmodesDir = path.join(projectDir, this.configDir, this.chatmodesDir);
// Clean up old chatmodes directory
const chatmodesDir = path.join(projectDir, this.configDir, 'chatmodes');
if (await fs.pathExists(chatmodesDir)) { if (await fs.pathExists(chatmodesDir)) {
// Only remove files that start with bmad- prefix
const files = await fs.readdir(chatmodesDir); const files = await fs.readdir(chatmodesDir);
let removed = 0; let removed = 0;
@ -293,7 +286,25 @@ ${cleanContent}
} }
if (removed > 0) { if (removed > 0) {
console.log(chalk.dim(` Cleaned up ${removed} existing BMAD chat modes`)); console.log(chalk.dim(` Cleaned up ${removed} old BMAD chat modes`));
}
}
// Clean up new agents directory
const agentsDir = path.join(projectDir, this.configDir, this.agentsDir);
if (await fs.pathExists(agentsDir)) {
const files = await fs.readdir(agentsDir);
let removed = 0;
for (const file of files) {
if (file.startsWith('bmd-') && file.endsWith('.agent.md')) {
await fs.remove(path.join(agentsDir, file));
removed++;
}
}
if (removed > 0) {
console.log(chalk.dim(` Cleaned up ${removed} existing BMAD agents`));
} }
} }
} }
@ -307,13 +318,13 @@ ${cleanContent}
* @returns {Object|null} Info about created command * @returns {Object|null} Info about created command
*/ */
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) { async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
const chatmodesDir = path.join(projectDir, this.configDir, this.chatmodesDir); const agentsDir = path.join(projectDir, this.configDir, this.agentsDir);
if (!(await this.exists(path.join(projectDir, this.configDir)))) { if (!(await this.exists(path.join(projectDir, this.configDir)))) {
return null; // IDE not configured for this project return null; // IDE not configured for this project
} }
await this.ensureDir(chatmodesDir); await this.ensureDir(agentsDir);
const launcherContent = `You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command. const launcherContent = `You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
@ -353,7 +364,7 @@ ${cleanContent}
'usages', 'usages',
]; ];
const chatmodeContent = `--- const agentContent = `---
description: "Activates the ${metadata.title || agentName} agent persona." description: "Activates the ${metadata.title || agentName} agent persona."
tools: ${JSON.stringify(copilotTools)} tools: ${JSON.stringify(copilotTools)}
--- ---
@ -363,12 +374,12 @@ tools: ${JSON.stringify(copilotTools)}
${launcherContent} ${launcherContent}
`; `;
const chatmodePath = path.join(chatmodesDir, `bmad-agent-custom-${agentName}.chatmode.md`); const agentFilePath = path.join(agentsDir, `bmd-custom-${agentName}.agent.md`);
await this.writeFile(chatmodePath, chatmodeContent); await this.writeFile(agentFilePath, agentContent);
return { return {
path: chatmodePath, path: agentFilePath,
command: `bmad-agent-custom-${agentName}`, command: `bmd-custom-${agentName}`,
}; };
} }
} }

View File

@ -123,6 +123,9 @@ class KiloSetup extends BaseIdeSetup {
modeEntry += ` groups:\n`; modeEntry += ` groups:\n`;
modeEntry += ` - read\n`; modeEntry += ` - read\n`;
modeEntry += ` - edit\n`; modeEntry += ` - edit\n`;
modeEntry += ` - browser\n`;
modeEntry += ` - command\n`;
modeEntry += ` - mcp\n`;
return modeEntry; return modeEntry;
} }

View File

@ -0,0 +1,290 @@
const path = require('node:path');
const fs = require('fs-extra');
const chalk = require('chalk');
const { BaseIdeSetup } = require('./_base-ide');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
/**
* Rovo Dev IDE setup handler
*
* Installs BMAD agents as Rovo Dev subagents in .rovodev/subagents/
* Installs workflows and tasks/tools as reference guides in .rovodev/
* Rovo Dev automatically discovers agents and integrates with BMAD like other IDEs
*/
class RovoDevSetup extends BaseIdeSetup {
constructor() {
super('rovo-dev', 'Atlassian Rovo Dev', true); // preferred IDE
this.configDir = '.rovodev';
this.subagentsDir = 'subagents';
this.workflowsDir = 'workflows';
this.referencesDir = 'references';
}
/**
* Cleanup old BMAD installation before reinstalling
* @param {string} projectDir - Project directory
*/
async cleanup(projectDir) {
const rovoDevDir = path.join(projectDir, this.configDir);
if (!(await fs.pathExists(rovoDevDir))) {
return;
}
// Clean BMAD agents from subagents directory
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
if (await fs.pathExists(subagentsDir)) {
const entries = await fs.readdir(subagentsDir);
const bmadFiles = entries.filter((file) => file.startsWith('bmad-') && file.endsWith('.md'));
for (const file of bmadFiles) {
await fs.remove(path.join(subagentsDir, file));
}
}
// Clean BMAD workflows from workflows directory
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
if (await fs.pathExists(workflowsDir)) {
const entries = await fs.readdir(workflowsDir);
const bmadFiles = entries.filter((file) => file.startsWith('bmad-') && file.endsWith('.md'));
for (const file of bmadFiles) {
await fs.remove(path.join(workflowsDir, file));
}
}
// Clean BMAD tasks/tools from references directory
const referencesDir = path.join(rovoDevDir, this.referencesDir);
if (await fs.pathExists(referencesDir)) {
const entries = await fs.readdir(referencesDir);
const bmadFiles = entries.filter((file) => file.startsWith('bmad-') && file.endsWith('.md'));
for (const file of bmadFiles) {
await fs.remove(path.join(referencesDir, file));
}
}
}
/**
* Setup Rovo Dev configuration
* @param {string} projectDir - Project directory
* @param {string} bmadDir - BMAD installation directory
* @param {Object} options - Setup options
*/
async setup(projectDir, bmadDir, options = {}) {
console.log(chalk.cyan(`Setting up ${this.name}...`));
// Clean up old BMAD installation first
await this.cleanup(projectDir);
// Create .rovodev directory structure
const rovoDevDir = path.join(projectDir, this.configDir);
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
const referencesDir = path.join(rovoDevDir, this.referencesDir);
await this.ensureDir(subagentsDir);
await this.ensureDir(workflowsDir);
await this.ensureDir(referencesDir);
// Generate and install agents
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
let agentCount = 0;
for (const artifact of agentArtifacts) {
const subagentFilename = `bmad-${artifact.module}-${artifact.name}.md`;
const targetPath = path.join(subagentsDir, subagentFilename);
const subagentContent = this.convertToRovoDevSubagent(artifact.content, artifact.name, artifact.module);
await this.writeFile(targetPath, subagentContent);
agentCount++;
}
// Generate and install workflows
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
let workflowCount = 0;
for (const artifact of workflowArtifacts) {
if (artifact.type === 'workflow-command') {
const workflowFilename = path.basename(artifact.relativePath);
const targetPath = path.join(workflowsDir, workflowFilename);
await this.writeFile(targetPath, artifact.content);
workflowCount++;
}
}
// Generate and install tasks and tools
const taskToolGen = new TaskToolCommandGenerator();
const { tasks: taskCount, tools: toolCount } = await this.generateTaskToolReferences(bmadDir, referencesDir, taskToolGen);
// Summary output
console.log(chalk.green(`${this.name} configured:`));
console.log(chalk.dim(` - ${agentCount} agents installed to .rovodev/subagents/`));
if (workflowCount > 0) {
console.log(chalk.dim(` - ${workflowCount} workflows installed to .rovodev/workflows/`));
}
if (taskCount + toolCount > 0) {
console.log(
chalk.dim(` - ${taskCount + toolCount} tasks/tools installed to .rovodev/references/ (${taskCount} tasks, ${toolCount} tools)`),
);
}
console.log(chalk.yellow(`\n Note: Agents are automatically discovered by Rovo Dev`));
console.log(chalk.dim(` - Access agents by typing @ in Rovo Dev to see available options`));
console.log(chalk.dim(` - Workflows and references are available in .rovodev/ directory`));
return {
success: true,
agents: agentCount,
workflows: workflowCount,
tasks: taskCount,
tools: toolCount,
};
}
/**
* Generate task and tool reference guides
* @param {string} bmadDir - BMAD directory
* @param {string} referencesDir - References directory
* @param {TaskToolCommandGenerator} taskToolGen - Generator instance
*/
async generateTaskToolReferences(bmadDir, referencesDir, taskToolGen) {
const tasks = await taskToolGen.loadTaskManifest(bmadDir);
const tools = await taskToolGen.loadToolManifest(bmadDir);
const standaloneTasks = tasks ? tasks.filter((t) => t.standalone === 'true' || t.standalone === true) : [];
const standaloneTools = tools ? tools.filter((t) => t.standalone === 'true' || t.standalone === true) : [];
let taskCount = 0;
for (const task of standaloneTasks) {
const commandContent = taskToolGen.generateCommandContent(task, 'task');
const targetPath = path.join(referencesDir, `bmad-task-${task.module}-${task.name}.md`);
await this.writeFile(targetPath, commandContent);
taskCount++;
}
let toolCount = 0;
for (const tool of standaloneTools) {
const commandContent = taskToolGen.generateCommandContent(tool, 'tool');
const targetPath = path.join(referencesDir, `bmad-tool-${tool.module}-${tool.name}.md`);
await this.writeFile(targetPath, commandContent);
toolCount++;
}
return { tasks: taskCount, tools: toolCount };
}
/**
* Convert BMAD agent launcher to Rovo Dev subagent format
*
* Rovo Dev subagents use Markdown files with YAML frontmatter containing:
* - name: Unique identifier for the subagent
* - description: One-line description of the subagent's purpose
* - tools: Array of tools the subagent can use (optional)
* - model: Specific model for this subagent (optional)
* - load_memory: Whether to load memory files (optional, defaults to true)
*
* @param {string} launcherContent - Original agent launcher content
* @param {string} agentName - Name of the agent
* @param {string} moduleName - Name of the module
* @returns {string} Rovo Dev subagent-formatted content
*/
convertToRovoDevSubagent(launcherContent, agentName, moduleName) {
// Extract metadata from the launcher XML
const titleMatch = launcherContent.match(/title="([^"]+)"/);
const title = titleMatch ? titleMatch[1] : this.formatTitle(agentName);
const descriptionMatch = launcherContent.match(/description="([^"]+)"/);
const description = descriptionMatch ? descriptionMatch[1] : `BMAD agent: ${title}`;
const roleDefinitionMatch = launcherContent.match(/roleDefinition="([^"]+)"/);
const roleDefinition = roleDefinitionMatch ? roleDefinitionMatch[1] : `You are a specialized agent for ${title.toLowerCase()} tasks.`;
// Extract the main system prompt from the launcher (content after closing tags)
let systemPrompt = roleDefinition;
// Try to extract additional instructions from the launcher content
const instructionsMatch = launcherContent.match(/<instructions>([\s\S]*?)<\/instructions>/);
if (instructionsMatch) {
systemPrompt += '\n\n' + instructionsMatch[1].trim();
}
// Build YAML frontmatter for Rovo Dev subagent
const frontmatter = {
name: `bmad-${moduleName}-${agentName}`,
description: description,
// Note: tools and model can be added by users in their .rovodev/subagents/*.md files
// We don't enforce specific tools since BMAD agents are flexible
};
// Create YAML frontmatter string with proper quoting for special characters
let yamlContent = '---\n';
yamlContent += `name: ${frontmatter.name}\n`;
// Quote description to handle colons and other special characters in YAML
yamlContent += `description: "${frontmatter.description.replaceAll('"', String.raw`\"`)}"\n`;
yamlContent += '---\n';
// Combine frontmatter with system prompt
const subagentContent = yamlContent + systemPrompt;
return subagentContent;
}
/**
* Detect whether Rovo Dev is already configured in the project
* @param {string} projectDir - Project directory
* @returns {boolean}
*/
async detect(projectDir) {
const rovoDevDir = path.join(projectDir, this.configDir);
if (!(await fs.pathExists(rovoDevDir))) {
return false;
}
// Check for BMAD agents in subagents directory
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
if (await fs.pathExists(subagentsDir)) {
try {
const entries = await fs.readdir(subagentsDir);
if (entries.some((entry) => entry.startsWith('bmad-') && entry.endsWith('.md'))) {
return true;
}
} catch {
// Continue checking other directories
}
}
// Check for BMAD workflows in workflows directory
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
if (await fs.pathExists(workflowsDir)) {
try {
const entries = await fs.readdir(workflowsDir);
if (entries.some((entry) => entry.startsWith('bmad-') && entry.endsWith('.md'))) {
return true;
}
} catch {
// Continue checking other directories
}
}
// Check for BMAD tasks/tools in references directory
const referencesDir = path.join(rovoDevDir, this.referencesDir);
if (await fs.pathExists(referencesDir)) {
try {
const entries = await fs.readdir(referencesDir);
if (entries.some((entry) => entry.startsWith('bmad-') && entry.endsWith('.md'))) {
return true;
}
} catch {
// Continue
}
}
return false;
}
}
module.exports = { RovoDevSetup };

View File

@ -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 chalk = require('chalk');
const inquirer = require('inquirer'); const inquirer = require('inquirer');
const path = require('node:path'); const path = require('node:path');
@ -99,6 +119,9 @@ class UI {
const moduleChoices = await this.getModuleChoices(installedModuleIds); const moduleChoices = await this.getModuleChoices(installedModuleIds);
const selectedModules = await this.selectModules(moduleChoices); 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) // Collect IDE tool selection AFTER configuration prompts (fixes Windows/PowerShell hang)
// This allows text-based prompts to complete before the checkbox prompt // This allows text-based prompts to complete before the checkbox prompt
const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules); const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
@ -114,6 +137,8 @@ class UI {
ides: toolSelection.ides, ides: toolSelection.ides,
skipIde: toolSelection.skipIde, skipIde: toolSelection.skipIde,
coreConfig: coreConfig, // Pass collected core config to installer 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 // Resolve to the absolute path relative to the current working directory
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(), 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 Agents to Speak Out loud (powered by Agent Vibes? Claude Code only currently)',
default: false, // 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 }; module.exports = { UI };

View File

@ -55,6 +55,12 @@ platforms:
category: ide category: ide
description: "Enhanced Cline fork" description: "Enhanced Cline fork"
rovo:
name: "Rovo Dev"
preferred: false
category: ide
description: "Atlassian's AI coding assistant"
github-copilot: github-copilot:
name: "GitHub Copilot" name: "GitHub Copilot"
preferred: false preferred: false