Compare commits
47 Commits
b24df615d6
...
6850fc507c
| Author | SHA1 | Date |
|---|---|---|
|
|
6850fc507c | |
|
|
2b7f7ff421 | |
|
|
3360666c2a | |
|
|
59ed596392 | |
|
|
a2458a5537 | |
|
|
b73670700b | |
|
|
5a16c3a102 | |
|
|
58e0b6a634 | |
|
|
2785d382d5 | |
|
|
551a2ccb53 | |
|
|
3fc411d9c9 | |
|
|
ec30b580e7 | |
|
|
9e6e991b53 | |
|
|
dbdaae1be7 | |
|
|
1636bd5a55 | |
|
|
53045d35b1 | |
|
|
b3643af6dc | |
|
|
4ba6e19303 | |
|
|
38ab12da85 | |
|
|
0ae6799cb6 | |
|
|
e479b4164c | |
|
|
71a1c325f7 | |
|
|
59c58b2e2c | |
|
|
18ac3c931a | |
|
|
8fc7db7b97 | |
|
|
060d5562a4 | |
|
|
2bd6e9df1b | |
|
|
6886e3c8cd | |
|
|
1f5700ea14 | |
|
|
9700da9dc6 | |
|
|
0f18c4bcba | |
|
|
ae9b83388c | |
|
|
64c32d8c8c | |
|
|
eae4ad46a1 | |
|
|
a8758b0393 | |
|
|
ac081a27e8 | |
|
|
7c914ae8b2 | |
|
|
dadca29b09 | |
|
|
25f93a3b64 | |
|
|
0f708d0b89 | |
|
|
5fcdae02b5 | |
|
|
b8eeb78cff | |
|
|
b628eec9fd | |
|
|
f5d949b922 | |
|
|
6d1d7d0e72 | |
|
|
8b6a053d2e | |
|
|
460c27e29a |
|
|
@ -11,7 +11,6 @@ ignores:
|
|||
- .claude/**
|
||||
- .roo/**
|
||||
- .codex/**
|
||||
- .agentvibes/**
|
||||
- .kiro/**
|
||||
- sample-project/**
|
||||
- test-project-install/**
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@ This flexibility enables:
|
|||
|
||||
## Categories
|
||||
|
||||
- [Categories](#categories)
|
||||
- [Custom Stand-Alone Modules](#custom-stand-alone-modules)
|
||||
- [Custom Add-On Modules](#custom-add-on-modules)
|
||||
- [Custom Global Modules](#custom-global-modules)
|
||||
- [Custom Agents](#custom-agents)
|
||||
- [BMad Tiny Agents](#bmad-tiny-agents)
|
||||
- [Simple and Expert Agents](#simple-and-expert-agents)
|
||||
- [Custom Workflows](#custom-workflows)
|
||||
|
||||
## Custom Stand-Alone Modules
|
||||
|
|
@ -59,7 +62,6 @@ Similar to Custom Stand-Alone Modules, but designed to add functionality that ap
|
|||
|
||||
Examples include:
|
||||
|
||||
- The current TTS (Text-to-Speech) functionality for Claude, which will soon be converted to a global module
|
||||
- The core module, which is always installed and provides all agents with party mode and advanced elicitation capabilities
|
||||
- Installation and update tools that work with any BMad method configuration
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Type "exit" or "done" to conclude the session. Participating agents will say per
|
|||
## Example Party Compositions
|
||||
|
||||
| Topic | Typical Agents |
|
||||
|-------|---------------|
|
||||
| ---------------------- | ------------------------------------------------------------- |
|
||||
| **Product Strategy** | PM + Innovation Strategist (CIS) + Analyst |
|
||||
| **Technical Design** | Architect + Creative Problem Solver (CIS) + Game Architect |
|
||||
| **User Experience** | UX Designer + Design Thinking Coach (CIS) + Storyteller (CIS) |
|
||||
|
|
@ -78,7 +78,6 @@ Type "exit" or "done" to conclude the session. Participating agents will say per
|
|||
- **Intelligent agent selection** — Selects based on expertise needed
|
||||
- **Authentic personalities** — Each agent maintains their unique voice
|
||||
- **Natural cross-talk** — Agents reference and build on each other
|
||||
- **Optional TTS** — Voice configurations for each agent
|
||||
- **Graceful exit** — Personalized farewells
|
||||
|
||||
## Tips
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"version": "6.0.0-alpha.23",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.11.0",
|
||||
"@kayvan/markdown-tree-parser": "^1.6.1",
|
||||
"boxen": "^5.1.2",
|
||||
"chalk": "^4.1.2",
|
||||
|
|
@ -33,7 +34,6 @@
|
|||
"devDependencies": {
|
||||
"@astrojs/sitemap": "^3.6.0",
|
||||
"@astrojs/starlight": "^0.37.0",
|
||||
"@clack/prompts": "^0.11.0",
|
||||
"@eslint/js": "^9.33.0",
|
||||
"archiver": "^7.0.1",
|
||||
"astro": "^5.16.0",
|
||||
|
|
@ -759,7 +759,6 @@
|
|||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz",
|
||||
"integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picocolors": "^1.0.0",
|
||||
|
|
@ -770,7 +769,6 @@
|
|||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz",
|
||||
"integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@clack/core": "0.5.0",
|
||||
|
|
@ -12151,7 +12149,6 @@
|
|||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
|
|
@ -13398,7 +13395,6 @@
|
|||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sitemap": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<!-- if possible, run this in a separate subagent or process with read access to the project,
|
||||
but no context except the content to review -->
|
||||
|
||||
<task id="_bmad/core/tasks/review-adversarial-general.xml" name="Adversarial Review (General)">
|
||||
<task id="_bmad/core/tasks/review-adversarial-general.xml" name="Adversarial Review">
|
||||
<objective>Cynically review content and produce findings</objective>
|
||||
|
||||
<inputs>
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ After agent loading and introduction:
|
|||
- Handle missing or incomplete agent entries gracefully
|
||||
- Cross-reference manifest with actual agent files
|
||||
- Prepare agent selection logic for intelligent conversation routing
|
||||
- Set up TTS voice configurations for each agent
|
||||
|
||||
## NEXT STEP:
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
- 🎯 SELECT RELEVANT AGENTS based on topic analysis and expertise matching
|
||||
- 📋 MAINTAIN CHARACTER CONSISTENCY using merged agent personalities
|
||||
- 🔍 ENABLE NATURAL CROSS-TALK between agents for dynamic conversation
|
||||
- 💬 INTEGRATE TTS for each agent response immediately after text
|
||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
||||
|
||||
## EXECUTION PROTOCOLS:
|
||||
|
|
@ -21,7 +20,6 @@
|
|||
|
||||
- Complete agent roster with merged personalities is available
|
||||
- User topic and conversation history guide agent selection
|
||||
- Party mode is active with TTS integration enabled
|
||||
- Exit triggers: `*exit`, `goodbye`, `end party`, `quit`
|
||||
|
||||
## YOUR TASK:
|
||||
|
|
@ -116,19 +114,9 @@ Allow natural back-and-forth within the same response round for dynamic interact
|
|||
|
||||
### 6. Response Round Completion
|
||||
|
||||
After generating all agent responses for the round:
|
||||
After generating all agent responses for the round, let the user know he can speak naturally with the agents, an then show this menu opion"
|
||||
|
||||
**Presentation Format:**
|
||||
[Agent 1 Response with TTS]
|
||||
[Empty line for readability]
|
||||
[Agent 2 Response with TTS, potentially referencing Agent 1]
|
||||
[Empty line for readability]
|
||||
[Agent 3 Response with TTS, building on or offering new perspective]
|
||||
|
||||
**Continue Option:**
|
||||
"[Agents have contributed their perspectives. Ready for more discussion?]
|
||||
|
||||
[E] Exit Party Mode - End the collaborative session"
|
||||
`[E] Exit Party Mode - End the collaborative session`
|
||||
|
||||
### 7. Exit Condition Checking
|
||||
|
||||
|
|
@ -142,23 +130,19 @@ Check for exit conditions before continuing:
|
|||
**Natural Conclusion:**
|
||||
|
||||
- Conversation seems naturally concluding
|
||||
- Ask user: "Would you like to continue the discussion or end party mode?"
|
||||
- Respect user choice to continue or exit
|
||||
- Confirm if the user wants to exit party mode and go back to where they were or continue chatting. Do it in a conversational way with an agent in the party.
|
||||
|
||||
### 8. Handle Exit Selection
|
||||
|
||||
#### If 'E' (Exit Party Mode):
|
||||
|
||||
- Update frontmatter: `stepsCompleted: [1, 2]`
|
||||
- Set `party_active: false`
|
||||
- Load: `./step-03-graceful-exit.md`
|
||||
- Load read and execute: `./step-03-graceful-exit.md`
|
||||
|
||||
## SUCCESS METRICS:
|
||||
|
||||
✅ Intelligent agent selection based on topic analysis
|
||||
✅ Authentic in-character responses maintained consistently
|
||||
✅ Natural cross-talk and agent interactions enabled
|
||||
✅ TTS integration working for all agent responses
|
||||
✅ Question handling protocol followed correctly
|
||||
✅ [E] exit option presented after each response round
|
||||
✅ Conversation context and state maintained throughout
|
||||
|
|
@ -168,7 +152,6 @@ Check for exit conditions before continuing:
|
|||
|
||||
❌ Generic responses without character consistency
|
||||
❌ Poor agent selection not matching topic expertise
|
||||
❌ Missing TTS integration for agent responses
|
||||
❌ Ignoring user questions or exit triggers
|
||||
❌ Not enabling natural agent cross-talk and interactions
|
||||
❌ Continuing conversation without user input when questions asked
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ workflow_completed: true
|
|||
|
||||
- Clear any active conversation state
|
||||
- Reset agent selection cache
|
||||
- Finalize TTS session cleanup
|
||||
- Mark party mode workflow as completed
|
||||
|
||||
### 6. Exit Workflow
|
||||
|
|
@ -122,7 +121,6 @@ Thank you for using BMAD Party Mode for collaborative multi-agent discussions!"
|
|||
✅ Satisfying agent farewells generated in authentic character voices
|
||||
✅ Session highlights and contributions acknowledged meaningfully
|
||||
✅ Positive and appreciative closure atmosphere maintained
|
||||
✅ TTS integration working for farewell messages
|
||||
✅ Frontmatter properly updated with workflow completion
|
||||
✅ All workflow state cleaned up appropriately
|
||||
✅ User left with positive impression of collaborative experience
|
||||
|
|
|
|||
|
|
@ -178,18 +178,6 @@ If conversation naturally concludes:
|
|||
|
||||
---
|
||||
|
||||
## TTS INTEGRATION
|
||||
|
||||
Party mode includes Text-to-Speech for each agent response:
|
||||
|
||||
**TTS Protocol:**
|
||||
|
||||
- Trigger TTS immediately after each agent's text response
|
||||
- Use agent's merged voice configuration from manifest
|
||||
- Format: `Bash: .claude/hooks/bmad-speak.sh "[Agent Name]" "[Their response]"`
|
||||
|
||||
---
|
||||
|
||||
## MODERATION NOTES
|
||||
|
||||
**Quality Control:**
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
# Senior Developer Review - Validation Checklist
|
||||
|
||||
- [ ] Story file loaded from `{{story_path}}`
|
||||
- [ ] Story Status verified as reviewable (review)
|
||||
- [ ] Epic and Story IDs resolved ({{epic_num}}.{{story_num}})
|
||||
- [ ] Story Context located or warning recorded
|
||||
- [ ] Epic Tech Spec located or warning recorded
|
||||
- [ ] Architecture/standards docs loaded (as available)
|
||||
- [ ] Tech stack detected and documented
|
||||
- [ ] MCP doc search performed (or web fallback) and references captured
|
||||
- [ ] Acceptance Criteria cross-checked against implementation
|
||||
- [ ] File List reviewed and validated for completeness
|
||||
- [ ] Tests identified and mapped to ACs; gaps noted
|
||||
- [ ] Code quality review performed on changed files
|
||||
- [ ] Security review performed on changed files and dependencies
|
||||
- [ ] Outcome decided (Approve/Changes Requested/Blocked)
|
||||
- [ ] Review notes appended under "Senior Developer Review (AI)"
|
||||
- [ ] Change Log updated with review entry
|
||||
- [ ] Status updated according to settings (if enabled)
|
||||
- [ ] Sprint status synced (if sprint tracking enabled)
|
||||
- [ ] Story saved successfully
|
||||
|
||||
_Reviewer: {{user_name}} on {{date}}_
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
<workflow>
|
||||
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
|
||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
||||
<critical>Generate all documents in {document_output_language}</critical>
|
||||
|
||||
<critical>🔥 YOU ARE AN ADVERSARIAL CODE REVIEWER - Find what's wrong or missing! 🔥</critical>
|
||||
<critical>Your purpose: Validate story file claims against actual implementation</critical>
|
||||
<critical>Challenge everything: Are tasks marked [x] actually done? Are ACs really implemented?</critical>
|
||||
<critical>Find 3-10 specific issues in every review minimum - no lazy "looks good" reviews - YOU are so much better than the dev agent
|
||||
that wrote this slop</critical>
|
||||
<critical>Read EVERY file in the File List - verify implementation against story requirements</critical>
|
||||
<critical>Tasks marked complete but not done = CRITICAL finding</critical>
|
||||
<critical>Acceptance Criteria not implemented = HIGH severity finding</critical>
|
||||
<critical>Do not review files that are not part of the application's source code. Always exclude the _bmad/ and _bmad-output/ folders from the review. Always exclude IDE and CLI configuration folders like .cursor/ and .windsurf/ and .claude/</critical>
|
||||
|
||||
|
||||
<step n="1" goal="Load story and discover changes">
|
||||
<action>Use provided {{story_path}} or ask user which story file to review</action>
|
||||
<action>Read COMPLETE story file</action>
|
||||
<action>Set {{story_key}} = extracted key from filename (e.g., "1-2-user-authentication.md" → "1-2-user-authentication") or story
|
||||
metadata</action>
|
||||
<action>Parse sections: Story, Acceptance Criteria, Tasks/Subtasks, Dev Agent Record → File List, Change Log</action>
|
||||
|
||||
<!-- Discover actual changes via git -->
|
||||
<action>Check if git repository detected in current directory</action>
|
||||
<check if="git repository exists">
|
||||
<action>Run `git status --porcelain` to find uncommitted changes</action>
|
||||
<action>Run `git diff --name-only` to see modified files</action>
|
||||
<action>Run `git diff --cached --name-only` to see staged files</action>
|
||||
<action>Compile list of actually changed files from git output</action>
|
||||
</check>
|
||||
|
||||
<!-- Cross-reference story File List vs git reality -->
|
||||
<action>Compare story's Dev Agent Record → File List with actual git changes</action>
|
||||
<action>Note discrepancies:
|
||||
- Files in git but not in story File List
|
||||
- Files in story File List but no git changes
|
||||
- Missing documentation of what was actually changed
|
||||
</action>
|
||||
|
||||
<invoke-protocol name="discover_inputs" />
|
||||
<action>Load {project_context} for coding standards (if exists)</action>
|
||||
</step>
|
||||
|
||||
<step n="2" goal="Build review attack plan">
|
||||
<action>Extract ALL Acceptance Criteria from story</action>
|
||||
<action>Extract ALL Tasks/Subtasks with completion status ([x] vs [ ])</action>
|
||||
<action>From Dev Agent Record → File List, compile list of claimed changes</action>
|
||||
|
||||
<action>Create review plan:
|
||||
1. **AC Validation**: Verify each AC is actually implemented
|
||||
2. **Task Audit**: Verify each [x] task is really done
|
||||
3. **Code Quality**: Security, performance, maintainability
|
||||
4. **Test Quality**: Real tests vs placeholder bullshit
|
||||
</action>
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Execute adversarial review">
|
||||
<critical>VALIDATE EVERY CLAIM - Check git reality vs story claims</critical>
|
||||
|
||||
<!-- Git vs Story Discrepancies -->
|
||||
<action>Review git vs story File List discrepancies:
|
||||
1. **Files changed but not in story File List** → MEDIUM finding (incomplete documentation)
|
||||
2. **Story lists files but no git changes** → HIGH finding (false claims)
|
||||
3. **Uncommitted changes not documented** → MEDIUM finding (transparency issue)
|
||||
</action>
|
||||
|
||||
<!-- Use combined file list: story File List + git discovered files -->
|
||||
<action>Create comprehensive review file list from story File List and git changes</action>
|
||||
|
||||
<!-- AC Validation -->
|
||||
<action>For EACH Acceptance Criterion:
|
||||
1. Read the AC requirement
|
||||
2. Search implementation files for evidence
|
||||
3. Determine: IMPLEMENTED, PARTIAL, or MISSING
|
||||
4. If MISSING/PARTIAL → HIGH SEVERITY finding
|
||||
</action>
|
||||
|
||||
<!-- Task Completion Audit -->
|
||||
<action>For EACH task marked [x]:
|
||||
1. Read the task description
|
||||
2. Search files for evidence it was actually done
|
||||
3. **CRITICAL**: If marked [x] but NOT DONE → CRITICAL finding
|
||||
4. Record specific proof (file:line)
|
||||
</action>
|
||||
|
||||
<!-- Code Quality Deep Dive -->
|
||||
<action>For EACH file in comprehensive review list:
|
||||
1. **Security**: Look for injection risks, missing validation, auth issues
|
||||
2. **Performance**: N+1 queries, inefficient loops, missing caching
|
||||
3. **Error Handling**: Missing try/catch, poor error messages
|
||||
4. **Code Quality**: Complex functions, magic numbers, poor naming
|
||||
5. **Test Quality**: Are tests real assertions or placeholders?
|
||||
</action>
|
||||
|
||||
<check if="total_issues_found lt 3">
|
||||
<critical>NOT LOOKING HARD ENOUGH - Find more problems!</critical>
|
||||
<action>Re-examine code for:
|
||||
- Edge cases and null handling
|
||||
- Architecture violations
|
||||
- Documentation gaps
|
||||
- Integration issues
|
||||
- Dependency problems
|
||||
- Git commit message quality (if applicable)
|
||||
</action>
|
||||
<action>Find at least 3 more specific, actionable issues</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="4" goal="Present findings and fix them">
|
||||
<action>Categorize findings: HIGH (must fix), MEDIUM (should fix), LOW (nice to fix)</action>
|
||||
<action>Set {{fixed_count}} = 0</action>
|
||||
<action>Set {{action_count}} = 0</action>
|
||||
|
||||
<output>**🔥 CODE REVIEW FINDINGS, {user_name}!**
|
||||
|
||||
**Story:** {{story_file}}
|
||||
**Git vs Story Discrepancies:** {{git_discrepancy_count}} found
|
||||
**Issues Found:** {{high_count}} High, {{medium_count}} Medium, {{low_count}} Low
|
||||
|
||||
## 🔴 CRITICAL ISSUES
|
||||
- Tasks marked [x] but not actually implemented
|
||||
- Acceptance Criteria not implemented
|
||||
- Story claims files changed but no git evidence
|
||||
- Security vulnerabilities
|
||||
|
||||
## 🟡 MEDIUM ISSUES
|
||||
- Files changed but not documented in story File List
|
||||
- Uncommitted changes not tracked
|
||||
- Performance problems
|
||||
- Poor test coverage/quality
|
||||
- Code maintainability issues
|
||||
|
||||
## 🟢 LOW ISSUES
|
||||
- Code style improvements
|
||||
- Documentation gaps
|
||||
- Git commit message quality
|
||||
</output>
|
||||
|
||||
<ask>What should I do with these issues?
|
||||
|
||||
1. **Fix them automatically** - I'll update the code and tests
|
||||
2. **Create action items** - Add to story Tasks/Subtasks for later
|
||||
3. **Show me details** - Deep dive into specific issues
|
||||
|
||||
Choose [1], [2], or specify which issue to examine:</ask>
|
||||
|
||||
<check if="user chooses 1">
|
||||
<action>Fix all HIGH and MEDIUM issues in the code</action>
|
||||
<action>Add/update tests as needed</action>
|
||||
<action>Update File List in story if files changed</action>
|
||||
<action>Update story Dev Agent Record with fixes applied</action>
|
||||
<action>Set {{fixed_count}} = number of HIGH and MEDIUM issues fixed</action>
|
||||
<action>Set {{action_count}} = 0</action>
|
||||
</check>
|
||||
|
||||
<check if="user chooses 2">
|
||||
<action>Add "Review Follow-ups (AI)" subsection to Tasks/Subtasks</action>
|
||||
<action>For each issue: `- [ ] [AI-Review][Severity] Description [file:line]`</action>
|
||||
<action>Set {{action_count}} = number of action items created</action>
|
||||
<action>Set {{fixed_count}} = 0</action>
|
||||
</check>
|
||||
|
||||
<check if="user chooses 3">
|
||||
<action>Show detailed explanation with code examples</action>
|
||||
<action>Return to fix decision</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="5" goal="Update story status and sync sprint tracking">
|
||||
<!-- Determine new status based on review outcome -->
|
||||
<check if="all HIGH and MEDIUM issues fixed AND all ACs implemented">
|
||||
<action>Set {{new_status}} = "done"</action>
|
||||
<action>Update story Status field to "done"</action>
|
||||
</check>
|
||||
<check if="HIGH or MEDIUM issues remain OR ACs not fully implemented">
|
||||
<action>Set {{new_status}} = "in-progress"</action>
|
||||
<action>Update story Status field to "in-progress"</action>
|
||||
</check>
|
||||
<action>Save story file</action>
|
||||
|
||||
<!-- Determine sprint tracking status -->
|
||||
<check if="{sprint_status} file exists">
|
||||
<action>Set {{current_sprint_status}} = "enabled"</action>
|
||||
</check>
|
||||
<check if="{sprint_status} file does NOT exist">
|
||||
<action>Set {{current_sprint_status}} = "no-sprint-tracking"</action>
|
||||
</check>
|
||||
|
||||
<!-- Sync sprint-status.yaml when story status changes (only if sprint tracking enabled) -->
|
||||
<check if="{{current_sprint_status}} != 'no-sprint-tracking'">
|
||||
<action>Load the FULL file: {sprint_status}</action>
|
||||
<action>Find development_status key matching {{story_key}}</action>
|
||||
|
||||
<check if="{{new_status}} == 'done'">
|
||||
<action>Update development_status[{{story_key}}] = "done"</action>
|
||||
<action>Save file, preserving ALL comments and structure</action>
|
||||
<output>✅ Sprint status synced: {{story_key}} → done</output>
|
||||
</check>
|
||||
|
||||
<check if="{{new_status}} == 'in-progress'">
|
||||
<action>Update development_status[{{story_key}}] = "in-progress"</action>
|
||||
<action>Save file, preserving ALL comments and structure</action>
|
||||
<output>🔄 Sprint status synced: {{story_key}} → in-progress</output>
|
||||
</check>
|
||||
|
||||
<check if="story key not found in sprint status">
|
||||
<output>⚠️ Story file updated, but sprint-status sync failed: {{story_key}} not found in sprint-status.yaml</output>
|
||||
</check>
|
||||
</check>
|
||||
|
||||
<check if="{{current_sprint_status}} == 'no-sprint-tracking'">
|
||||
<output>ℹ️ Story status updated (no sprint tracking configured)</output>
|
||||
</check>
|
||||
|
||||
<output>**✅ Review Complete!**
|
||||
|
||||
**Story Status:** {{new_status}}
|
||||
**Issues Fixed:** {{fixed_count}}
|
||||
**Action Items Created:** {{action_count}}
|
||||
|
||||
{{#if new_status == "done"}}Code review complete!{{else}}Address the action items and continue development.{{/if}}
|
||||
</output>
|
||||
</step>
|
||||
|
||||
</workflow>
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
name: 'step-01-load-story'
|
||||
description: "Compare story's file list against git changes"
|
||||
---
|
||||
|
||||
# Step 1: Load Story and Discover Changes
|
||||
|
||||
---
|
||||
|
||||
## STATE VARIABLES (capture now, persist throughout)
|
||||
|
||||
These variables MUST be set in this step and available to all subsequent steps:
|
||||
|
||||
- `story_path` - Path to the story file being reviewed
|
||||
- `story_key` - Story identifier (e.g., "1-2-user-authentication")
|
||||
- `story_content` - Complete, unmodified file content from story_path (loaded in substep 2)
|
||||
- `story_file_list` - Files claimed in story's Dev Agent Record → File List
|
||||
- `git_changed_files` - Files actually changed according to git
|
||||
- `git_discrepancies` - Mismatches between `story_file_list` and `git_changed_files`
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION SEQUENCE
|
||||
|
||||
### 1. Identify Story
|
||||
|
||||
Ask user: "Which story would you like to review?"
|
||||
|
||||
**Try input as direct file path first:**
|
||||
If input resolves to an existing file:
|
||||
- Verify it's in {sprint_status} with status `review` or `done`
|
||||
- If verified → set `story_path` to that file path
|
||||
- If NOT verified → Warn user the file is not in {sprint_status} (or wrong status). Ask: "Continue anyway?"
|
||||
- If yes → set `story_path`
|
||||
- If no → return to user prompt (ask "Which story would you like to review?" again)
|
||||
|
||||
**Search {sprint_status}** (if input is not a direct file):
|
||||
Search for stories with status `review` or `done`. Match by priority:
|
||||
1. Story number resembles input closely enough (e.g., "1-2" matches "1 2", "1.2", "one dash two", "one two"; "1-32" matches "one thirty two"). Do NOT match if numbers differ (e.g., "1-33" does not match "1-32")
|
||||
2. Exact story name/key (e.g., "1-2-user-auth-api")
|
||||
3. Story name/title resembles input closely enough
|
||||
4. Story description resembles input closely enough
|
||||
|
||||
**Resolution:**
|
||||
- **Single match**: Confident. Set `story_path`, proceed to substep 2
|
||||
- **Multiple matches**: Uncertain. Present all candidates to user. Wait for selection. Set `story_path`, proceed to substep 2
|
||||
- **No match**: Ask user to clarify or provide the full story path. Return to user prompt (ask "Which story would you like to review?" again)
|
||||
|
||||
### 2. Load Story File
|
||||
|
||||
**Load file content:**
|
||||
Read the complete contents of {story_path} and assign to `story_content` WITHOUT filtering, truncating or summarizing. If {story_path} cannot be read, is empty, or obviously doesn't have the story: report the error to the user and HALT the workflow.
|
||||
|
||||
**Extract story identifier:**
|
||||
Verify the filename ends with `.md` extension. Remove `.md` to get `story_key` (e.g., "1-2-user-authentication.md" → "1-2-user-authentication"). If filename doesn't end with `.md` or the result is empty: report the error to the user and HALT the workflow.
|
||||
|
||||
### 3. Extract File List from Story
|
||||
|
||||
Extract `story_file_list` from the Dev Agent Record → File List section of {story_content}.
|
||||
|
||||
**If Dev Agent Record or File List section not found:** Report to user and set `story_file_list` = NO_FILE_LIST.
|
||||
|
||||
### 4. Discover Git Changes
|
||||
|
||||
Check if git repository exists.
|
||||
|
||||
**If NOT a git repo:** Set `git_changed_files` = NO_GIT, `git_discrepancies` = NO_GIT. Skip to substep 5.
|
||||
|
||||
**If git repo detected:**
|
||||
|
||||
```bash
|
||||
git status --porcelain
|
||||
git diff -M --name-only
|
||||
git diff -M --cached --name-only
|
||||
```
|
||||
|
||||
If any git command fails: Report the error to the user and HALT the workflow.
|
||||
|
||||
Compile `git_changed_files` = union of modified, staged, new, deleted, and renamed files.
|
||||
|
||||
### 5. Cross-Reference Story vs Git
|
||||
|
||||
**If {git_changed_files} is empty:**
|
||||
|
||||
Ask user: "No git changes detected. Continue anyway?"
|
||||
|
||||
- If **no**: HALT the workflow
|
||||
- If **yes**: Continue to comparison
|
||||
|
||||
**Compare {story_file_list} with {git_changed_files}:**
|
||||
|
||||
Exclude git-ignored files from the comparison (run `git check-ignore` if needed).
|
||||
|
||||
Set `git_discrepancies` with categories:
|
||||
|
||||
- **files_in_git_not_story**: Files changed in git but not in story File List
|
||||
- **files_in_story_not_git**: Files in story File List but no git changes (excluding git-ignored)
|
||||
- **uncommitted_undocumented**: Uncommitted changes not tracked in story
|
||||
|
||||
---
|
||||
|
||||
## COMPLETION CHECKLIST
|
||||
|
||||
Before proceeding to the next step, verify ALL of the following:
|
||||
|
||||
- `story_path` identified and loaded
|
||||
- `story_key` extracted
|
||||
- `story_content` captured completely and unmodified
|
||||
- `story_file_list` compiled from Dev Agent Record (or NO_FILE_LIST if not found)
|
||||
- `git_changed_files` discovered via git commands (or NO_GIT if not a git repo)
|
||||
- `git_discrepancies` calculated
|
||||
|
||||
**If any criterion is not met:** Report to the user and HALT the workflow.
|
||||
|
||||
---
|
||||
|
||||
## NEXT STEP DIRECTIVE
|
||||
|
||||
**CRITICAL:** When this step completes, explicitly state:
|
||||
|
||||
"**NEXT:** Loading `step-02-build-attack-plan.md`"
|
||||
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
---
|
||||
name: 'step-02-adversarial-review'
|
||||
description: 'Lean adversarial review - context-independent diff analysis, no story knowledge'
|
||||
---
|
||||
|
||||
# Step 2: Adversarial Review (Information Asymmetric)
|
||||
|
||||
**Goal:** Perform context-independent adversarial review of code changes. Reviewer sees ONLY the diff - no story, no ACs, no context about WHY changes were made.
|
||||
|
||||
<critical>Reviewer has FULL repo access but NO knowledge of WHY changes were made</critical>
|
||||
<critical>DO NOT include story file in prompt - asymmetry is about intent, not visibility</critical>
|
||||
<critical>This catches issues a fresh reviewer would find that story-biased review might miss</critical>
|
||||
|
||||
---
|
||||
|
||||
## AVAILABLE STATE
|
||||
|
||||
From previous steps:
|
||||
|
||||
- `{story_path}`, `{story_key}`
|
||||
- `{file_list}` - Files listed in story's File List section
|
||||
- `{git_changed_files}` - Files changed according to git
|
||||
- `{baseline_commit}` - From story file Dev Agent Record
|
||||
|
||||
---
|
||||
|
||||
## STATE VARIABLE (capture now)
|
||||
|
||||
- `{diff_output}` - Complete diff of changes
|
||||
- `{asymmetric_findings}` - Findings from adversarial review
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION SEQUENCE
|
||||
|
||||
### 1. Construct Diff
|
||||
|
||||
Build complete diff of all changes for this story.
|
||||
|
||||
**Step 1a: Read baseline from story file**
|
||||
|
||||
Extract `Baseline Commit` from the story file's Dev Agent Record section.
|
||||
|
||||
- If found and not "NO_GIT": use as `{baseline_commit}`
|
||||
- If "NO_GIT" or missing: proceed to fallback
|
||||
|
||||
**Step 1b: Construct diff (with baseline)**
|
||||
|
||||
If `{baseline_commit}` is a valid commit hash:
|
||||
|
||||
```bash
|
||||
git diff {baseline_commit} -- ':!{implementation_artifacts}'
|
||||
```
|
||||
|
||||
This captures all changes (committed + uncommitted) since dev-story started.
|
||||
|
||||
**Step 1c: Fallback (no baseline)**
|
||||
|
||||
If no baseline available, review current state of files in `{file_list}`:
|
||||
|
||||
- Read each file listed in the story's File List section
|
||||
- Review as full file content (not a diff)
|
||||
|
||||
**Include in `{diff_output}`:**
|
||||
|
||||
- All modified tracked files (except files in `{implementation_artifacts}` - asymmetry requires hiding intent)
|
||||
- All new files created for this story
|
||||
- Full content for new files
|
||||
|
||||
**Note:** Do NOT `git add` anything - this is read-only inspection.
|
||||
|
||||
### 2. Invoke Adversarial Review
|
||||
|
||||
With `{diff_output}` constructed, invoke the review task. If possible, use information asymmetry: run this step, and only it, in a separate subagent or process with read access to the project, but no context except the `{diff_output}`.
|
||||
|
||||
```xml
|
||||
<invoke-task>Review {diff_output} using {project-root}/_bmad/core/tasks/review-adversarial-general.xml</invoke-task>
|
||||
```
|
||||
|
||||
**Platform fallback:** If task invocation not available, load the task file and execute its instructions inline, passing `{diff_output}` as the content.
|
||||
|
||||
The task should: review `{diff_output}` and return a list of findings.
|
||||
|
||||
### 3. Process Adversarial Findings
|
||||
|
||||
Capture findings from adversarial review.
|
||||
|
||||
**If zero findings:** HALT - this is suspicious. Re-analyze or ask for guidance.
|
||||
|
||||
Evaluate severity (Critical, High, Medium, Low) and validity (Real, Noise, Undecided).
|
||||
|
||||
Add each finding to `{asymmetric_findings}` (no IDs yet - assigned after merge):
|
||||
|
||||
```
|
||||
{
|
||||
source: "adversarial",
|
||||
severity: "...",
|
||||
validity: "...",
|
||||
description: "...",
|
||||
location: "file:line (if applicable)"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Phase 1 Summary
|
||||
|
||||
Present adversarial findings:
|
||||
|
||||
```
|
||||
**Phase 1: Adversarial Review Complete**
|
||||
|
||||
**Reviewer Context:** Pure diff review (no story knowledge)
|
||||
**Findings:** {count}
|
||||
- Critical: {count}
|
||||
- High: {count}
|
||||
- Medium: {count}
|
||||
- Low: {count}
|
||||
|
||||
**Validity Assessment:**
|
||||
- Real: {count}
|
||||
- Noise: {count}
|
||||
- Undecided: {count}
|
||||
|
||||
Proceeding to attack plan construction...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NEXT STEP DIRECTIVE
|
||||
|
||||
**CRITICAL:** When this step completes, explicitly state:
|
||||
|
||||
"**NEXT:** Loading `step-03-build-attack-plan.md`"
|
||||
|
||||
---
|
||||
|
||||
## SUCCESS METRICS
|
||||
|
||||
- Diff constructed from correct source (uncommitted or commits)
|
||||
- Story file excluded from diff
|
||||
- Task invoked with diff as input
|
||||
- Adversarial review executed
|
||||
- Findings captured with severity and validity
|
||||
- `{asymmetric_findings}` populated
|
||||
- Phase summary presented
|
||||
- Explicit NEXT directive provided
|
||||
|
||||
## FAILURE MODES
|
||||
|
||||
- Including story file in diff (breaks asymmetry)
|
||||
- Skipping adversarial review entirely
|
||||
- Accepting zero findings without halt
|
||||
- Invoking task without providing diff input
|
||||
- Missing severity/validity classification
|
||||
- Not storing findings for consolidation
|
||||
- No explicit NEXT directive at step completion
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
---
|
||||
name: 'step-03-build-attack-plan'
|
||||
description: 'Extract ACs and tasks, create comprehensive review plan for context-aware phase'
|
||||
---
|
||||
|
||||
# Step 3: Build Review Attack Plan
|
||||
|
||||
**Goal:** Extract all reviewable items from story and create attack plan for context-aware review phase.
|
||||
|
||||
---
|
||||
|
||||
## AVAILABLE STATE
|
||||
|
||||
From previous steps:
|
||||
|
||||
- `{story_path}` - Path to the story file
|
||||
- `{story_key}` - Story identifier
|
||||
- `{story_file_list}` - Files claimed in story
|
||||
- `{git_changed_files}` - Files actually changed (git)
|
||||
- `{git_discrepancies}` - Differences between claims and reality
|
||||
- `{asymmetric_findings}` - Findings from Phase 1 (adversarial review)
|
||||
|
||||
---
|
||||
|
||||
## STATE VARIABLES (capture now)
|
||||
|
||||
- `{acceptance_criteria}` - All ACs extracted from story
|
||||
- `{tasks_with_status}` - All tasks with their [x] or [ ] status
|
||||
- `{comprehensive_file_list}` - Union of story files + git files
|
||||
- `{review_attack_plan}` - Structured plan for context-aware phase
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION SEQUENCE
|
||||
|
||||
### 1. Extract Acceptance Criteria
|
||||
|
||||
Parse all Acceptance Criteria from story:
|
||||
|
||||
```
|
||||
{acceptance_criteria} = [
|
||||
{ id: "AC1", requirement: "...", testable: true/false },
|
||||
{ id: "AC2", requirement: "...", testable: true/false },
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
Note any ACs that are vague or untestable.
|
||||
|
||||
### 2. Extract Tasks with Status
|
||||
|
||||
Parse all Tasks/Subtasks with completion markers:
|
||||
|
||||
```
|
||||
{tasks_with_status} = [
|
||||
{ id: "T1", description: "...", status: "complete" ([x]) or "incomplete" ([ ]) },
|
||||
{ id: "T1.1", description: "...", status: "complete" or "incomplete" },
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
Flag any tasks marked complete [x] for verification.
|
||||
|
||||
### 3. Build Comprehensive File List
|
||||
|
||||
Merge `{story_file_list}` and `{git_changed_files}`:
|
||||
|
||||
```
|
||||
{comprehensive_file_list} = union of:
|
||||
- Files in story Dev Agent Record
|
||||
- Files changed according to git
|
||||
- Deduped and sorted
|
||||
```
|
||||
|
||||
Exclude from review:
|
||||
|
||||
- `_bmad/`, `_bmad-output/`
|
||||
- `.cursor/`, `.windsurf/`, `.claude/`
|
||||
- IDE/editor config files
|
||||
|
||||
### 4. Create Review Attack Plan
|
||||
|
||||
Structure the `{review_attack_plan}`:
|
||||
|
||||
```
|
||||
PHASE 1: Adversarial Review (Step 2) [COMPLETE - {asymmetric_findings} findings]
|
||||
├── Fresh code review without story context
|
||||
│ └── {asymmetric_findings} items to consolidate
|
||||
|
||||
PHASE 2: Context-Aware Review (Step 4)
|
||||
├── Git vs Story Discrepancies
|
||||
│ └── {git_discrepancies} items
|
||||
├── AC Validation
|
||||
│ └── {acceptance_criteria} items to verify
|
||||
├── Task Completion Audit
|
||||
│ └── {tasks_with_status} marked [x] to verify
|
||||
└── Code Quality Review
|
||||
└── {comprehensive_file_list} files to review
|
||||
```
|
||||
|
||||
### 5. Preview Attack Plan
|
||||
|
||||
Present to user (brief summary):
|
||||
|
||||
```
|
||||
**Review Attack Plan**
|
||||
|
||||
**Story:** {story_key}
|
||||
|
||||
**Phase 1 (Adversarial - Complete):** {asymmetric_findings count} findings from fresh review
|
||||
**Phase 2 (Context-Aware - Starting):**
|
||||
- ACs to verify: {count}
|
||||
- Tasks marked complete: {count}
|
||||
- Files to review: {count}
|
||||
- Git discrepancies detected: {count}
|
||||
|
||||
Proceeding with context-aware review...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NEXT STEP DIRECTIVE
|
||||
|
||||
**CRITICAL:** When this step completes, explicitly state:
|
||||
|
||||
"**NEXT:** Loading `step-04-context-aware-review.md`"
|
||||
|
||||
---
|
||||
|
||||
## SUCCESS METRICS
|
||||
|
||||
- All ACs extracted with testability assessment
|
||||
- All tasks extracted with completion status
|
||||
- Comprehensive file list built (story + git)
|
||||
- Exclusions applied correctly
|
||||
- Attack plan structured for context-aware phase
|
||||
- Summary presented to user
|
||||
- Explicit NEXT directive provided
|
||||
|
||||
## FAILURE MODES
|
||||
|
||||
- Missing AC extraction
|
||||
- Not capturing task completion status
|
||||
- Forgetting to merge story + git files
|
||||
- Not excluding IDE/config directories
|
||||
- Skipping attack plan structure
|
||||
- No explicit NEXT directive at step completion
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
---
|
||||
name: 'step-04-context-aware-review'
|
||||
description: 'Story-aware validation: verify ACs, audit task completion, check git discrepancies'
|
||||
---
|
||||
|
||||
# Step 4: Context-Aware Review
|
||||
|
||||
**Goal:** Perform story-aware validation - verify AC implementation, audit task completion, review code quality with full story context.
|
||||
|
||||
<critical>VALIDATE EVERY CLAIM - Check git reality vs story claims</critical>
|
||||
<critical>You KNOW the story requirements - use that knowledge to find gaps</critical>
|
||||
|
||||
---
|
||||
|
||||
## AVAILABLE STATE
|
||||
|
||||
From previous steps:
|
||||
|
||||
- `{story_path}`, `{story_key}`
|
||||
- `{story_file_list}`, `{git_changed_files}`, `{git_discrepancies}`
|
||||
- `{acceptance_criteria}`, `{tasks_with_status}`
|
||||
- `{comprehensive_file_list}`, `{review_attack_plan}`
|
||||
- `{asymmetric_findings}` - From Phase 1 (adversarial review)
|
||||
|
||||
---
|
||||
|
||||
## STATE VARIABLE (capture now)
|
||||
|
||||
- `{context_aware_findings}` - All findings from this phase
|
||||
|
||||
Initialize `{context_aware_findings}` as empty list.
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION SEQUENCE
|
||||
|
||||
### 0. Load Planning Context (JIT)
|
||||
|
||||
Load planning documents for AC validation against system design:
|
||||
|
||||
- **Architecture**: `{planning_artifacts}/*architecture*.md` (or sharded: `{planning_artifacts}/*architecture*/*.md`)
|
||||
- **UX Design**: `{planning_artifacts}/*ux*.md` (if UI review relevant)
|
||||
- **Epic**: `{planning_artifacts}/*epic*/epic-{epic_num}.md` (the epic containing this story)
|
||||
|
||||
These provide the design context needed to validate AC implementation against system requirements.
|
||||
|
||||
### 1. Git vs Story Discrepancies
|
||||
|
||||
Review `{git_discrepancies}` and create findings:
|
||||
|
||||
| Discrepancy Type | Severity |
|
||||
| --- | --- |
|
||||
| Files changed but not in story File List | Medium |
|
||||
| Story lists files but no git changes | High |
|
||||
| Uncommitted changes not documented | Medium |
|
||||
|
||||
For each discrepancy, add to `{context_aware_findings}` (no IDs yet - assigned after merge):
|
||||
|
||||
```
|
||||
{
|
||||
source: "git-discrepancy",
|
||||
severity: "...",
|
||||
description: "...",
|
||||
evidence: "file: X, git says: Y, story says: Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Acceptance Criteria Validation
|
||||
|
||||
For EACH AC in `{acceptance_criteria}`:
|
||||
|
||||
1. Read the AC requirement
|
||||
2. Search implementation files in `{comprehensive_file_list}` for evidence
|
||||
3. Determine status: IMPLEMENTED, PARTIAL, or MISSING
|
||||
4. If PARTIAL or MISSING → add High severity finding
|
||||
|
||||
Add to `{context_aware_findings}`:
|
||||
|
||||
```
|
||||
{
|
||||
source: "ac-validation",
|
||||
severity: "High",
|
||||
description: "AC {id} not fully implemented: {details}",
|
||||
evidence: "Expected: {ac}, Found: {what_was_found}"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Task Completion Audit
|
||||
|
||||
For EACH task marked [x] in `{tasks_with_status}`:
|
||||
|
||||
1. Read the task description
|
||||
2. Search files for evidence it was actually done
|
||||
3. **Critical**: If marked [x] but NOT DONE → Critical finding
|
||||
4. Record specific proof (file:line) if done
|
||||
|
||||
Add to `{context_aware_findings}` if false:
|
||||
|
||||
```
|
||||
{
|
||||
source: "task-audit",
|
||||
severity: "Critical",
|
||||
description: "Task marked complete but not implemented: {task}",
|
||||
evidence: "Searched: {files}, Found: no evidence of {expected}"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Code Quality Review (Context-Aware)
|
||||
|
||||
For EACH file in `{comprehensive_file_list}`:
|
||||
|
||||
Review with STORY CONTEXT (you know what was supposed to be built):
|
||||
|
||||
- **Security**: Missing validation for AC-specified inputs?
|
||||
- **Performance**: Story mentioned scale requirements met?
|
||||
- **Error Handling**: Edge cases from AC covered?
|
||||
- **Test Quality**: Tests actually verify ACs or just placeholders?
|
||||
- **Architecture Compliance**: Follows patterns in architecture doc?
|
||||
|
||||
Add findings to `{context_aware_findings}` with appropriate severity.
|
||||
|
||||
### 5. Minimum Finding Check
|
||||
|
||||
<critical>If total findings < 3, NOT LOOKING HARD ENOUGH</critical>
|
||||
|
||||
Re-examine for:
|
||||
|
||||
- Edge cases not covered by implementation
|
||||
- Documentation gaps
|
||||
- Integration issues with other components
|
||||
- Dependency problems
|
||||
- Comments missing for complex logic
|
||||
|
||||
---
|
||||
|
||||
## PHASE 2 SUMMARY
|
||||
|
||||
Present context-aware findings:
|
||||
|
||||
```
|
||||
**Phase 2: Context-Aware Review Complete**
|
||||
|
||||
**Findings:** {count}
|
||||
- Critical: {count}
|
||||
- High: {count}
|
||||
- Medium: {count}
|
||||
- Low: {count}
|
||||
|
||||
Proceeding to findings consolidation...
|
||||
```
|
||||
|
||||
Store `{context_aware_findings}` for consolidation in step 5.
|
||||
|
||||
---
|
||||
|
||||
## NEXT STEP DIRECTIVE
|
||||
|
||||
**CRITICAL:** When this step completes, explicitly state:
|
||||
|
||||
"**NEXT:** Loading `step-05-consolidate-findings.md`"
|
||||
|
||||
---
|
||||
|
||||
## SUCCESS METRICS
|
||||
|
||||
- All git discrepancies reviewed and findings created
|
||||
- Every AC checked for implementation evidence
|
||||
- Every [x] task verified with proof
|
||||
- Code quality reviewed with story context
|
||||
- Minimum 3 findings (push harder if not)
|
||||
- `{context_aware_findings}` populated
|
||||
- Phase summary presented
|
||||
- Explicit NEXT directive provided
|
||||
|
||||
## FAILURE MODES
|
||||
|
||||
- Accepting "looks good" with < 3 findings
|
||||
- Not verifying [x] tasks with actual evidence
|
||||
- Missing AC validation
|
||||
- Ignoring git discrepancies
|
||||
- Not storing findings for consolidation
|
||||
- No explicit NEXT directive at step completion
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
---
|
||||
name: 'step-05-consolidate-findings'
|
||||
description: 'Merge and deduplicate findings from both review phases'
|
||||
---
|
||||
|
||||
# Step 5: Consolidate Findings
|
||||
|
||||
**Goal:** Merge findings from adversarial review (Phase 1) and context-aware review (Phase 2), deduplicate, and present unified findings table.
|
||||
|
||||
---
|
||||
|
||||
## AVAILABLE STATE
|
||||
|
||||
From previous steps:
|
||||
|
||||
- `{story_path}`, `{story_key}`
|
||||
- `{asymmetric_findings}` - Findings from Phase 1 (step 2 - adversarial review)
|
||||
- `{context_aware_findings}` - Findings from Phase 2 (step 4 - context-aware review)
|
||||
|
||||
---
|
||||
|
||||
## STATE VARIABLE (capture now)
|
||||
|
||||
- `{consolidated_findings}` - Merged, deduplicated findings
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION SEQUENCE
|
||||
|
||||
### 1. Merge All Findings
|
||||
|
||||
Combine both finding lists:
|
||||
|
||||
```
|
||||
all_findings = {context_aware_findings} + {asymmetric_findings}
|
||||
```
|
||||
|
||||
### 2. Deduplicate Findings
|
||||
|
||||
Identify duplicates (same underlying issue found by both phases):
|
||||
|
||||
**Duplicate Detection Criteria:**
|
||||
|
||||
- Same file + same line range
|
||||
- Same issue type (e.g., both about error handling in same function)
|
||||
- Overlapping descriptions
|
||||
|
||||
**Resolution Rule:**
|
||||
|
||||
Keep the MORE DETAILED version:
|
||||
|
||||
- If context-aware finding has AC reference → keep that
|
||||
- If adversarial finding has better technical detail → keep that
|
||||
- When in doubt, keep context-aware (has more context)
|
||||
|
||||
Note which findings were merged (for transparency in the summary).
|
||||
|
||||
### 3. Normalize Severity
|
||||
|
||||
Apply consistent severity scale (Critical, High, Medium, Low).
|
||||
|
||||
### 4. Filter Noise
|
||||
|
||||
Review adversarial findings marked as Noise:
|
||||
|
||||
- If clearly false positive (e.g., style preference, not actual issue) → exclude
|
||||
- If questionable → keep with Undecided validity
|
||||
- If context reveals it's actually valid → upgrade to Real
|
||||
|
||||
**Do NOT filter:**
|
||||
|
||||
- Any Critical or High severity
|
||||
- Any context-aware findings (they have story context)
|
||||
|
||||
### 5. Sort and Number Findings
|
||||
|
||||
Sort by severity (Critical → High → Medium → Low), then assign IDs: F1, F2, F3, etc.
|
||||
|
||||
Build `{consolidated_findings}`:
|
||||
|
||||
```markdown
|
||||
| ID | Severity | Source | Description | Location |
|
||||
|----|----------|--------|-------------|----------|
|
||||
| F1 | Critical | task-audit | Task 3 marked [x] but not implemented | src/auth.ts |
|
||||
| F2 | High | ac-validation | AC2 partially implemented | src/api/*.ts |
|
||||
| F3 | High | adversarial | Missing error handling in API calls | src/api/client.ts:45 |
|
||||
| F4 | Medium | git-discrepancy | File changed but not in story | src/utils.ts |
|
||||
| F5 | Low | adversarial | Magic number should be constant | src/config.ts:12 |
|
||||
```
|
||||
|
||||
### 6. Present Consolidated Findings
|
||||
|
||||
```markdown
|
||||
**Consolidated Code Review Findings**
|
||||
|
||||
**Story:** {story_key}
|
||||
|
||||
**Summary:**
|
||||
- Total findings: {count}
|
||||
- Critical: {count}
|
||||
- High: {count}
|
||||
- Medium: {count}
|
||||
- Low: {count}
|
||||
|
||||
**Deduplication:** {merged_count} duplicate findings merged
|
||||
|
||||
---
|
||||
|
||||
## Findings by Severity
|
||||
|
||||
### Critical (Must Fix)
|
||||
{list critical findings with full details}
|
||||
|
||||
### High (Should Fix)
|
||||
{list high findings with full details}
|
||||
|
||||
### Medium (Consider Fixing)
|
||||
{list medium findings}
|
||||
|
||||
### Low (Nice to Fix)
|
||||
{list low findings}
|
||||
|
||||
---
|
||||
|
||||
**Phase Sources:**
|
||||
- Adversarial (Phase 1): {count} findings
|
||||
- Context-Aware (Phase 2): {count} findings
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NEXT STEP DIRECTIVE
|
||||
|
||||
**CRITICAL:** When this step completes, explicitly state:
|
||||
|
||||
"**NEXT:** Loading `step-06-resolve-and-update.md`"
|
||||
|
||||
---
|
||||
|
||||
## SUCCESS METRICS
|
||||
|
||||
- All findings merged from both phases
|
||||
- Duplicates identified and resolved (kept more detailed)
|
||||
- Severity normalized consistently
|
||||
- Noise filtered appropriately (but not excessively)
|
||||
- Consolidated table created
|
||||
- `{consolidated_findings}` populated
|
||||
- Summary presented to user
|
||||
- Explicit NEXT directive provided
|
||||
|
||||
## FAILURE MODES
|
||||
|
||||
- Missing findings from either phase
|
||||
- Not detecting duplicates (double-counting issues)
|
||||
- Inconsistent severity assignment
|
||||
- Filtering real issues as noise
|
||||
- Not storing consolidated findings
|
||||
- No explicit NEXT directive at step completion
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
---
|
||||
name: 'step-06-resolve-and-update'
|
||||
description: 'Present findings, fix or create action items, update story and sprint status'
|
||||
---
|
||||
|
||||
# Step 6: Resolve Findings and Update Status
|
||||
|
||||
**Goal:** Present findings to user, handle resolution (fix or action items), update story file and sprint status.
|
||||
|
||||
---
|
||||
|
||||
## AVAILABLE STATE
|
||||
|
||||
From previous steps:
|
||||
|
||||
- `{story_path}`, `{story_key}`
|
||||
- `{consolidated_findings}` - Merged findings from step 5
|
||||
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
|
||||
|
||||
---
|
||||
|
||||
## STATE VARIABLES (capture now)
|
||||
|
||||
- `{fixed_count}` - Number of issues fixed
|
||||
- `{action_count}` - Number of action items created
|
||||
- `{new_status}` - Final story status
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION SEQUENCE
|
||||
|
||||
### 1. Present Resolution Options
|
||||
|
||||
```markdown
|
||||
**Code Review Findings for {user_name}**
|
||||
|
||||
**Story:** {story_key}
|
||||
**Total Issues:** {consolidated_findings.count}
|
||||
|
||||
{consolidated_findings_table}
|
||||
|
||||
---
|
||||
|
||||
**What should I do with these issues?**
|
||||
|
||||
**[1] Fix them automatically** - I'll update the code and tests
|
||||
**[2] Create action items** - Add to story Tasks/Subtasks for later
|
||||
**[3] Walk through** - Discuss each finding individually
|
||||
**[4] Show details** - Deep dive into specific issues
|
||||
|
||||
Choose [1], [2], [3], [4], or specify which issue (e.g., "CF-3"):
|
||||
```
|
||||
|
||||
### 2. Handle User Choice
|
||||
|
||||
**Option [1]: Fix Automatically**
|
||||
|
||||
1. For each CRITICAL and HIGH finding:
|
||||
- Apply the fix in the code
|
||||
- Add/update tests if needed
|
||||
- Record what was fixed
|
||||
2. Update story Dev Agent Record → File List if files changed
|
||||
3. Add "Code Review Fixes Applied" entry to Change Log
|
||||
4. Set `{fixed_count}` = number of issues fixed
|
||||
5. Set `{action_count}` = 0 (LOW findings can become action items)
|
||||
|
||||
**Option [2]: Create Action Items**
|
||||
|
||||
1. Add "Review Follow-ups (AI)" subsection to Tasks/Subtasks
|
||||
2. For each finding:
|
||||
```
|
||||
- [ ] [AI-Review][{severity}] {description} [{location}]
|
||||
```
|
||||
3. Set `{action_count}` = number of action items created
|
||||
4. Set `{fixed_count}` = 0
|
||||
|
||||
**Option [3]: Walk Through**
|
||||
|
||||
For each finding in order:
|
||||
|
||||
1. Present finding with full context and code snippet
|
||||
2. Ask: **[f]ix now / [s]kip / [d]iscuss more**
|
||||
3. If fix: Apply fix immediately, increment `{fixed_count}`
|
||||
4. If skip: Note as acknowledged, optionally create action item
|
||||
5. If discuss: Provide more detail, repeat choice
|
||||
6. Continue to next finding
|
||||
|
||||
After all processed, summarize what was fixed/skipped.
|
||||
|
||||
**Option [4]: Show Details**
|
||||
|
||||
1. Present expanded details for specific finding(s)
|
||||
2. Return to resolution choice
|
||||
|
||||
### 3. Determine Final Status
|
||||
|
||||
Evaluate completion:
|
||||
|
||||
**If ALL conditions met:**
|
||||
|
||||
- All CRITICAL issues fixed
|
||||
- All HIGH issues fixed or have action items
|
||||
- All ACs verified as implemented
|
||||
|
||||
Set `{new_status}` = "done"
|
||||
|
||||
**Otherwise:**
|
||||
|
||||
Set `{new_status}` = "in-progress"
|
||||
|
||||
### 4. Update Story File
|
||||
|
||||
1. Update story Status field to `{new_status}`
|
||||
2. Add review notes to Dev Agent Record:
|
||||
|
||||
```markdown
|
||||
## Senior Developer Review (AI)
|
||||
|
||||
**Date:** {date}
|
||||
**Reviewer:** AI Code Review
|
||||
|
||||
**Findings Summary:**
|
||||
- CRITICAL: {count} ({fixed}/{action_items})
|
||||
- HIGH: {count} ({fixed}/{action_items})
|
||||
- MEDIUM: {count}
|
||||
- LOW: {count}
|
||||
|
||||
**Resolution:** {approach_taken}
|
||||
|
||||
**Files Modified:** {list if fixes applied}
|
||||
```
|
||||
|
||||
3. Update Change Log:
|
||||
|
||||
```markdown
|
||||
- [{date}] Code review completed - {outcome_summary}
|
||||
```
|
||||
|
||||
4. Save story file
|
||||
|
||||
### 5. Sync Sprint Status
|
||||
|
||||
Check if `{sprint_status}` file exists:
|
||||
|
||||
**If exists:**
|
||||
|
||||
1. Load `{sprint_status}`
|
||||
2. Find `{story_key}` in development_status
|
||||
3. Update status to `{new_status}`
|
||||
4. Save file, preserving ALL comments and structure
|
||||
|
||||
```
|
||||
Sprint status synced: {story_key} {new_status}
|
||||
```
|
||||
|
||||
**If not exists or key not found:**
|
||||
|
||||
```
|
||||
Sprint status sync skipped (no sprint tracking or key not found)
|
||||
```
|
||||
|
||||
### 6. Completion Output
|
||||
|
||||
```markdown
|
||||
** Code Review Complete!**
|
||||
|
||||
**Story:** {story_key}
|
||||
**Final Status:** {new_status}
|
||||
**Issues Fixed:** {fixed_count}
|
||||
**Action Items Created:** {action_count}
|
||||
|
||||
{if new_status == "done"}
|
||||
Code review passed! Story is ready for final verification.
|
||||
{else}
|
||||
Address the action items and run another review cycle.
|
||||
{endif}
|
||||
|
||||
---
|
||||
|
||||
**Next Steps:**
|
||||
- Commit changes (if fixes applied)
|
||||
- Run tests to verify fixes
|
||||
- Address remaining action items (if any)
|
||||
- Mark story complete when all items resolved
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WORKFLOW COMPLETE
|
||||
|
||||
This is the final step. The Code Review workflow is now complete.
|
||||
|
||||
---
|
||||
|
||||
## SUCCESS METRICS
|
||||
|
||||
- Resolution options presented clearly
|
||||
- User choice handled correctly
|
||||
- Fixes applied cleanly (if chosen)
|
||||
- Action items created correctly (if chosen)
|
||||
- Story status determined correctly
|
||||
- Story file updated with review notes
|
||||
- Sprint status synced (if applicable)
|
||||
- Completion summary provided
|
||||
|
||||
## FAILURE MODES
|
||||
|
||||
- Not presenting resolution options
|
||||
- Fixing without user consent
|
||||
- Not updating story file
|
||||
- Wrong status determination (done when issues remain)
|
||||
- Not syncing sprint status when it exists
|
||||
- Missing completion summary
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
name: code-review
|
||||
description: 'Code review for dev-story output. Audits acceptance criteria against implementation, performs adversarial diff review, can auto-fix with approval. A different LLM than the implementer is recommended.'
|
||||
web_bundle: false
|
||||
---
|
||||
|
||||
# Code Review Workflow
|
||||
|
||||
## WORKFLOW ARCHITECTURE: STEP FILES
|
||||
|
||||
- This file (workflow.md) stays in context throughout
|
||||
- Each step file is read just before processing (current step stays at end of context)
|
||||
- State persists via variables: `{story_path}`, `{story_key}`, `{context_aware_findings}`, `{asymmetric_findings}`
|
||||
|
||||
---
|
||||
|
||||
## INITIALIZATION
|
||||
|
||||
### Configuration Loading
|
||||
|
||||
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
||||
|
||||
- `user_name`, `communication_language`, `user_skill_level`, `document_output_language`
|
||||
- `planning_artifacts`, `implementation_artifacts`
|
||||
- `date` as system-generated current datetime
|
||||
|
||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
||||
|
||||
### Paths
|
||||
|
||||
- `installed_path` = `{project-root}/_bmad/bmm/workflows/4-implementation/code-review`
|
||||
- `project_context` = `**/project-context.md` (load if exists)
|
||||
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION
|
||||
|
||||
Read and follow `steps/step-01-load-story.md` to begin the workflow.
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# Review Story Workflow
|
||||
name: code-review
|
||||
description: "Perform an ADVERSARIAL Senior Developer code review that finds 3-10 specific problems in every story. Challenges everything: code quality, test coverage, architecture compliance, security, performance. NEVER accepts `looks good` - must find minimum issues and can auto-fix with user approval."
|
||||
author: "BMad"
|
||||
|
||||
# Critical variables from config
|
||||
config_source: "{project-root}/_bmad/bmm/config.yaml"
|
||||
user_name: "{config_source}:user_name"
|
||||
communication_language: "{config_source}:communication_language"
|
||||
user_skill_level: "{config_source}:user_skill_level"
|
||||
document_output_language: "{config_source}:document_output_language"
|
||||
date: system-generated
|
||||
planning_artifacts: "{config_source}:planning_artifacts"
|
||||
implementation_artifacts: "{config_source}:implementation_artifacts"
|
||||
output_folder: "{implementation_artifacts}"
|
||||
sprint_status: "{implementation_artifacts}/sprint-status.yaml"
|
||||
|
||||
# Workflow components
|
||||
installed_path: "{project-root}/_bmad/bmm/workflows/4-implementation/code-review"
|
||||
instructions: "{installed_path}/instructions.xml"
|
||||
validation: "{installed_path}/checklist.md"
|
||||
template: false
|
||||
|
||||
variables:
|
||||
# Project context
|
||||
project_context: "**/project-context.md"
|
||||
story_dir: "{implementation_artifacts}"
|
||||
|
||||
# Smart input file references - handles both whole docs and sharded docs
|
||||
# Priority: Whole document first, then sharded version
|
||||
# Strategy: SELECTIVE LOAD - only load the specific epic needed for this story review
|
||||
input_file_patterns:
|
||||
architecture:
|
||||
description: "System architecture for review context"
|
||||
whole: "{planning_artifacts}/*architecture*.md"
|
||||
sharded: "{planning_artifacts}/*architecture*/*.md"
|
||||
load_strategy: "FULL_LOAD"
|
||||
ux_design:
|
||||
description: "UX design specification (if UI review)"
|
||||
whole: "{planning_artifacts}/*ux*.md"
|
||||
sharded: "{planning_artifacts}/*ux*/*.md"
|
||||
load_strategy: "FULL_LOAD"
|
||||
epics:
|
||||
description: "Epic containing story being reviewed"
|
||||
whole: "{planning_artifacts}/*epic*.md"
|
||||
sharded_index: "{planning_artifacts}/*epic*/index.md"
|
||||
sharded_single: "{planning_artifacts}/*epic*/epic-{{epic_num}}.md"
|
||||
load_strategy: "SELECTIVE_LOAD"
|
||||
|
||||
standalone: true
|
||||
web_bundle: false
|
||||
|
|
@ -219,6 +219,17 @@
|
|||
<output>ℹ️ No sprint status file exists - story progress will be tracked in story file only</output>
|
||||
<action>Set {{current_sprint_status}} = "no-sprint-tracking"</action>
|
||||
</check>
|
||||
|
||||
<!-- Capture baseline commit for code review -->
|
||||
<check if="git is available">
|
||||
<action>Capture current HEAD commit: `git rev-parse HEAD`</action>
|
||||
<action>Store as {{baseline_commit}}</action>
|
||||
<action>Write to story file Dev Agent Record: "**Baseline Commit:** {{baseline_commit}}"</action>
|
||||
</check>
|
||||
<check if="git is NOT available">
|
||||
<action>Set {{baseline_commit}} = "NO_GIT"</action>
|
||||
<action>Write to story file Dev Agent Record: "**Baseline Commit:** NO_GIT"</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="5" goal="Implement task following red-green-refactor cycle">
|
||||
|
|
|
|||
|
|
@ -51,7 +51,11 @@ Use best-effort diff construction:
|
|||
|
||||
### Capture as {diff_output}
|
||||
|
||||
Merge all changes into `{diff_output}`.
|
||||
**Include in `{diff_output}`:**
|
||||
|
||||
- All modified tracked files (except `{tech_spec_path}` if tech-spec mode - asymmetry requires hiding intent)
|
||||
- All new files created during this workflow
|
||||
- Full content for new files
|
||||
|
||||
**Note:** Do NOT `git add` anything - this is read-only inspection.
|
||||
|
||||
|
|
@ -75,7 +79,7 @@ The task should: review `{diff_output}` and return a list of findings.
|
|||
|
||||
Capture the findings from the task output.
|
||||
**If zero findings:** HALT - this is suspicious. Re-analyze or request user guidance.
|
||||
Evaluate severity (Critical, High, Medium, Low) and validity (real, noise, undecided).
|
||||
Evaluate severity (Critical, High, Medium, Low) and validity (Real, Noise, Undecided).
|
||||
DO NOT exclude findings based on severity or validity unless explicitly asked to do so.
|
||||
Order findings by severity.
|
||||
Number the ordered findings (F1, F2, F3, etc.).
|
||||
|
|
@ -92,6 +96,7 @@ With findings in hand, load `step-06-resolve-findings.md` for user to choose res
|
|||
## SUCCESS METRICS
|
||||
|
||||
- Diff constructed from baseline_commit
|
||||
- Tech-spec excluded from diff when in tech-spec mode (information asymmetry)
|
||||
- New files included in diff
|
||||
- Task invoked with diff as input
|
||||
- Findings received
|
||||
|
|
@ -100,6 +105,7 @@ With findings in hand, load `step-06-resolve-findings.md` for user to choose res
|
|||
## FAILURE MODES
|
||||
|
||||
- Missing baseline_commit (can't construct accurate diff)
|
||||
- Including tech_spec_path in diff when in tech-spec mode (breaks asymmetry)
|
||||
- Not including new untracked files in diff
|
||||
- Invoking task without providing diff input
|
||||
- Accepting zero findings without questioning
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<rules>
|
||||
<r>ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.</r>
|
||||
<!-- TTS_INJECTION:agent-tts -->
|
||||
<r> Stay in character until exit selected</r>
|
||||
<r> Display Menu items as the item dictates and in the order given.</r>
|
||||
<r> Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml</r>
|
||||
|
|
|
|||
|
|
@ -62,40 +62,6 @@ module.exports = {
|
|||
|
||||
// Check if installation succeeded
|
||||
if (result && result.success) {
|
||||
// Run AgentVibes installer if needed
|
||||
if (result.needsAgentVibes) {
|
||||
// Add some spacing before AgentVibes setup
|
||||
console.log('');
|
||||
console.log(chalk.magenta('🎙️ AgentVibes TTS Setup'));
|
||||
console.log(chalk.cyan('AgentVibes provides voice synthesis for BMAD agents with:'));
|
||||
console.log(chalk.dim(' • ElevenLabs AI (150+ premium voices)'));
|
||||
console.log(chalk.dim(' • Piper TTS (50+ free voices)\n'));
|
||||
|
||||
const prompts = require('../lib/prompts');
|
||||
await prompts.text({
|
||||
message: chalk.green('Press Enter to start AgentVibes installer...'),
|
||||
});
|
||||
|
||||
console.log('');
|
||||
|
||||
// Run AgentVibes installer
|
||||
const { execSync } = require('node:child_process');
|
||||
try {
|
||||
execSync('npx agentvibes@latest install', {
|
||||
cwd: result.projectDir,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
});
|
||||
console.log(chalk.green('\n✓ AgentVibes installation complete'));
|
||||
console.log(chalk.cyan('\n✨ BMAD with TTS is ready to use!'));
|
||||
} catch {
|
||||
console.log(chalk.yellow('\n⚠ AgentVibes installation was interrupted or failed'));
|
||||
console.log(chalk.cyan('You can run it manually later with:'));
|
||||
console.log(chalk.green(` cd ${result.projectDir}`));
|
||||
console.log(chalk.green(' npx agentvibes install\n'));
|
||||
}
|
||||
}
|
||||
|
||||
// Display version-specific end message from install-messages.yaml
|
||||
const { MessageLoader } = require('../installers/lib/message-loader');
|
||||
const messageLoader = new MessageLoader();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ class Installer {
|
|||
this.configCollector = new ConfigCollector();
|
||||
this.ideConfigManager = new IdeConfigManager();
|
||||
this.installedFiles = new Set(); // Track all installed files
|
||||
this.ttsInjectedFiles = []; // Track files with TTS injection applied
|
||||
this.bmadFolderName = BMAD_FOLDER_NAME;
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +68,7 @@ class Installer {
|
|||
/**
|
||||
* @function copyFileWithPlaceholderReplacement
|
||||
* @intent Copy files from BMAD source to installation directory with dynamic content transformation
|
||||
* @why Enables installation-time customization: _bmad replacement + optional AgentVibes TTS injection
|
||||
* @why Enables installation-time customization: _bmad replacement
|
||||
* @param {string} sourcePath - Absolute path to source file in BMAD repository
|
||||
* @param {string} targetPath - Absolute path to destination file in user's project
|
||||
* @param {string} bmadFolderName - User's chosen bmad folder name (default: 'bmad')
|
||||
|
|
@ -77,24 +76,9 @@ class Installer {
|
|||
* @sideeffects Writes transformed file to targetPath, creates parent directories if needed
|
||||
* @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()
|
||||
* @calls fs.readFile(), fs.writeFile(), fs.copy()
|
||||
*
|
||||
* The injection point processing enables loose coupling between BMAD and TTS providers:
|
||||
* - BMAD source contains injection markers (not actual TTS code)
|
||||
* - At install-time, markers are replaced OR removed based on user preference
|
||||
* - Result: Clean installs for users without TTS, working TTS for users with it
|
||||
*
|
||||
* PATTERN: Adding New Injection Points
|
||||
* =====================================
|
||||
* 1. Add HTML comment marker in BMAD source file:
|
||||
* <!-- TTS_INJECTION:feature-name -->
|
||||
*
|
||||
* 2. Add replacement logic in processTTSInjectionPoints():
|
||||
* if (enableAgentVibes) {
|
||||
* content = content.replace(/<!-- TTS_INJECTION:feature-name -->/g, 'actual code');
|
||||
* } else {
|
||||
* content = content.replace(/<!-- TTS_INJECTION:feature-name -->\n?/g, '');
|
||||
* }
|
||||
|
||||
*
|
||||
* 3. Document marker in instructions.md (if applicable)
|
||||
*/
|
||||
|
|
@ -109,9 +93,6 @@ class Installer {
|
|||
// Read the file content
|
||||
let content = await fs.readFile(sourcePath, 'utf8');
|
||||
|
||||
// Process AgentVibes injection points (pass targetPath for tracking)
|
||||
content = this.processTTSInjectionPoints(content, targetPath);
|
||||
|
||||
// Write to target with replaced content
|
||||
await fs.ensureDir(path.dirname(targetPath));
|
||||
await fs.writeFile(targetPath, content, 'utf8');
|
||||
|
|
@ -125,116 +106,6 @@ class Installer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @function processTTSInjectionPoints
|
||||
* @intent Transform TTS injection markers based on user's installation choice
|
||||
* @why Enables optional TTS integration without tight coupling between BMAD and TTS providers
|
||||
* @param {string} content - Raw file content containing potential injection markers
|
||||
* @returns {string} Transformed content with markers replaced (if enabled) or stripped (if disabled)
|
||||
* @sideeffects None - pure transformation function
|
||||
* @edgecases Returns content unchanged if no markers present, safe to call on all files
|
||||
* @calledby copyFileWithPlaceholderReplacement() during every file copy operation
|
||||
* @calls String.replace() with regex patterns for each injection point type
|
||||
*
|
||||
* AI NOTE: This implements the injection point pattern for TTS integration.
|
||||
* Key architectural decisions:
|
||||
*
|
||||
* 1. **Why Injection Points vs Direct Integration?**
|
||||
* - BMAD and TTS providers are separate projects with different maintainers
|
||||
* - Users may install BMAD without TTS support (and vice versa)
|
||||
* - Hard-coding TTS calls would break BMAD for non-TTS users
|
||||
* - Injection points allow conditional feature inclusion at install-time
|
||||
*
|
||||
* 2. **How It Works:**
|
||||
* - BMAD source contains markers: <!-- TTS_INJECTION:feature-name -->
|
||||
* - During installation, user is prompted: "Enable AgentVibes TTS?"
|
||||
* - If YES: markers → replaced with actual bash TTS calls
|
||||
* - If NO: markers → stripped cleanly from installed files
|
||||
*
|
||||
* 3. **State Management:**
|
||||
* - this.enableAgentVibes set in install() method from config.enableAgentVibes
|
||||
* - config.enableAgentVibes comes from ui.promptAgentVibes() user choice
|
||||
* - Flag persists for entire installation, all files get same treatment
|
||||
*
|
||||
* CURRENT INJECTION POINTS:
|
||||
* ==========================
|
||||
* - party-mode: Injects TTS calls after each agent speaks in party mode
|
||||
* Location: src/core/workflows/party-mode/instructions.md
|
||||
* Marker: <!-- TTS_INJECTION:party-mode -->
|
||||
* Replacement: Bash call to .claude/hooks/bmad-speak.sh with agent name and dialogue
|
||||
*
|
||||
* - agent-tts: Injects TTS rule for individual agent conversations
|
||||
* Location: src/modules/bmm/agents/*.md (all agent files)
|
||||
* Marker: <!-- TTS_INJECTION:agent-tts -->
|
||||
* Replacement: Rule instructing agent to call bmad-speak.sh with agent ID and response
|
||||
*
|
||||
* ADDING NEW INJECTION POINTS:
|
||||
* =============================
|
||||
* 1. Add new case in this function:
|
||||
* content = content.replace(
|
||||
* /<!-- TTS_INJECTION:new-feature -->/g,
|
||||
* `code to inject when enabled`
|
||||
* );
|
||||
*
|
||||
* 2. Add marker to BMAD source file at injection location
|
||||
*
|
||||
* 3. Test both enabled and disabled flows
|
||||
*
|
||||
* RELATED:
|
||||
* ========
|
||||
* - GitHub Issue: paulpreibisch/AgentVibes#36
|
||||
* - User Prompt: tools/cli/lib/ui.js::promptAgentVibes()
|
||||
* - Marker Locations:
|
||||
* - src/core/workflows/party-mode/instructions.md:101
|
||||
* - src/modules/bmm/agents/*.md (rules sections)
|
||||
* - TTS Hook: .claude/hooks/bmad-speak.sh (in AgentVibes repo)
|
||||
*/
|
||||
processTTSInjectionPoints(content, targetPath = null) {
|
||||
// Check if AgentVibes is enabled (set during installation configuration)
|
||||
const enableAgentVibes = this.enableAgentVibes || false;
|
||||
|
||||
// Check if content contains any TTS injection markers
|
||||
const hasPartyMode = content.includes('<!-- TTS_INJECTION:party-mode -->');
|
||||
const hasAgentTTS = content.includes('<!-- TTS_INJECTION:agent-tts -->');
|
||||
|
||||
if (enableAgentVibes) {
|
||||
// Replace party-mode injection marker with actual TTS call
|
||||
// Use single quotes to prevent shell expansion of special chars like !
|
||||
content = content.replaceAll(
|
||||
'<!-- TTS_INJECTION:party-mode -->',
|
||||
`<critical>IMPORTANT: Always use PROJECT hooks (.claude/hooks/), NEVER global hooks (~/.claude/hooks/)</critical>
|
||||
|
||||
If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||
- Use Bash tool: \`.claude/hooks/bmad-speak.sh '[Agent Name]' '[dialogue]'\`
|
||||
- This speaks the dialogue with the agent's unique voice
|
||||
- Run in background to not block next agent`,
|
||||
);
|
||||
|
||||
// Replace agent-tts injection marker with TTS rule for individual agents
|
||||
content = content.replaceAll(
|
||||
'<!-- TTS_INJECTION:agent-tts -->',
|
||||
`- When responding to user messages, speak your responses using TTS:
|
||||
Call: \`.claude/hooks/bmad-speak.sh '{agent-id}' '{response-text}'\` after each response
|
||||
Replace {agent-id} with YOUR agent ID from <agent id="..."> tag at top of this file
|
||||
Replace {response-text} with the text you just output to the user
|
||||
IMPORTANT: Use single quotes as shown - do NOT escape special characters like ! or $ inside single quotes
|
||||
Run in background (&) to avoid blocking`,
|
||||
);
|
||||
|
||||
// Track files that had TTS injection applied
|
||||
if (targetPath && (hasPartyMode || hasAgentTTS)) {
|
||||
const injectionType = hasPartyMode ? 'party-mode' : 'agent-tts';
|
||||
this.ttsInjectedFiles.push({ path: targetPath, type: injectionType });
|
||||
}
|
||||
} else {
|
||||
// Strip injection markers cleanly when AgentVibes is disabled
|
||||
content = content.replaceAll(/<!-- TTS_INJECTION:party-mode -->\n?/g, '');
|
||||
content = content.replaceAll(/<!-- TTS_INJECTION:agent-tts -->\n?/g, '');
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Tool/IDE configurations after module configuration
|
||||
* @param {string} projectDir - Project directory
|
||||
|
|
@ -251,7 +122,7 @@ class Installer {
|
|||
// Fallback: prompt for tool selection (backwards compatibility)
|
||||
const { UI } = require('../../../lib/ui');
|
||||
const ui = new UI();
|
||||
toolConfig = await ui.promptToolSelection(projectDir, selectedModules);
|
||||
toolConfig = await ui.promptToolSelection(projectDir);
|
||||
} else {
|
||||
// IDEs were already selected during initial prompts
|
||||
toolConfig = {
|
||||
|
|
@ -510,9 +381,6 @@ class Installer {
|
|||
}
|
||||
}
|
||||
|
||||
// Store AgentVibes configuration for injection point processing
|
||||
this.enableAgentVibes = config.enableAgentVibes || false;
|
||||
|
||||
// Set bmad folder name on module manager and IDE manager for placeholder replacement
|
||||
this.moduleManager.setBmadFolderName(BMAD_FOLDER_NAME);
|
||||
this.moduleManager.setCoreConfig(moduleConfigs.core || {});
|
||||
|
|
@ -1234,8 +1102,6 @@ class Installer {
|
|||
modules: config.modules,
|
||||
ides: config.ides,
|
||||
customFiles: customFiles.length > 0 ? customFiles : undefined,
|
||||
ttsInjectedFiles: this.enableAgentVibes && this.ttsInjectedFiles.length > 0 ? this.ttsInjectedFiles : undefined,
|
||||
agentVibesEnabled: this.enableAgentVibes || false,
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
@ -1243,7 +1109,6 @@ class Installer {
|
|||
path: bmadDir,
|
||||
modules: config.modules,
|
||||
ides: config.ides,
|
||||
needsAgentVibes: this.enableAgentVibes && !config.agentVibesInstalled,
|
||||
projectDir: projectDir,
|
||||
};
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ class AntigravitySetup extends BaseIdeSetup {
|
|||
};
|
||||
|
||||
const selected = await prompts.multiselect({
|
||||
message: `Select subagents to install ${chalk.dim('(↑/↓ navigate, SPACE select, ENTER confirm)')}:`,
|
||||
message: `Select subagents to install ${chalk.dim('(↑/↓ navigates multiselect, SPACE toggles, A to toggles All, ENTER confirm)')}:`,
|
||||
choices: subagentConfig.files.map((file) => ({
|
||||
name: `${file.replace('.md', '')} - ${subagentInfo[file] || 'Specialized assistant'}`,
|
||||
value: file,
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ class ClaudeCodeSetup extends BaseIdeSetup {
|
|||
};
|
||||
|
||||
const selected = await prompts.multiselect({
|
||||
message: `Select subagents to install ${chalk.dim('(↑/↓ navigate, SPACE select, ENTER confirm)')}:`,
|
||||
message: `Select subagents to install ${chalk.dim('(↑/↓ navigates multiselect, SPACE toggles, A to toggles All, ENTER confirm)')}:`,
|
||||
options: subagentConfig.files.map((file) => ({
|
||||
label: `${file.replace('.md', '')} - ${subagentInfo[file] || 'Specialized assistant'}`,
|
||||
value: file,
|
||||
|
|
|
|||
|
|
@ -845,14 +845,8 @@ class ModuleManager {
|
|||
// Compile with customizations if any
|
||||
const { xml } = await compileAgent(yamlContent, answers, agentName, relativePath, { config: this.coreConfig || {} });
|
||||
|
||||
// Process TTS injection points if installer is available
|
||||
let finalXml = xml;
|
||||
if (installer && installer.processTTSInjectionPoints) {
|
||||
finalXml = installer.processTTSInjectionPoints(xml, targetMdPath);
|
||||
}
|
||||
|
||||
// Write the compiled agent
|
||||
await fs.writeFile(targetMdPath, finalXml, 'utf8');
|
||||
await fs.writeFile(targetMdPath, xml, 'utf8');
|
||||
|
||||
// Handle sidecar copying if present
|
||||
if (hasSidecar) {
|
||||
|
|
|
|||
|
|
@ -478,39 +478,10 @@ function filterCustomizationData(data) {
|
|||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process TTS injection markers in content
|
||||
* @param {string} content - Content to process
|
||||
* @param {boolean} enableAgentVibes - Whether AgentVibes is enabled
|
||||
* @returns {Object} { content: string, hadInjection: boolean }
|
||||
*/
|
||||
function processTTSInjectionPoints(content, enableAgentVibes) {
|
||||
const hasAgentTTS = content.includes('<!-- TTS_INJECTION:agent-tts -->');
|
||||
|
||||
if (enableAgentVibes && hasAgentTTS) {
|
||||
// Replace agent-tts injection marker with TTS rule
|
||||
content = content.replaceAll(
|
||||
'<!-- TTS_INJECTION:agent-tts -->',
|
||||
`- When responding to user messages, speak your responses using TTS:
|
||||
Call: \`.claude/hooks/bmad-speak.sh '{agent-id}' '{response-text}'\` after each response
|
||||
Replace {agent-id} with YOUR agent ID from <agent id="..."> tag at top of this file
|
||||
Replace {response-text} with the text you just output to the user
|
||||
IMPORTANT: Use single quotes as shown - do NOT escape special characters like ! or $ inside single quotes
|
||||
Run in background (&) to avoid blocking`,
|
||||
);
|
||||
return { content, hadInjection: true };
|
||||
} else if (!enableAgentVibes && hasAgentTTS) {
|
||||
// Strip injection markers when disabled
|
||||
content = content.replaceAll(/<!-- TTS_INJECTION:agent-tts -->\n?/g, '');
|
||||
}
|
||||
|
||||
return { content, hadInjection: false };
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile agent file to .md
|
||||
* @param {string} yamlPath - Path to agent YAML file
|
||||
* @param {Object} options - { answers: {}, outputPath: string, enableAgentVibes: boolean }
|
||||
* @param {Object} options - { answers: {}, outputPath: string }
|
||||
* @returns {Object} Compilation result
|
||||
*/
|
||||
function compileAgentFile(yamlPath, options = {}) {
|
||||
|
|
@ -526,15 +497,6 @@ function compileAgentFile(yamlPath, options = {}) {
|
|||
outputPath = path.join(dir, `${basename}.md`);
|
||||
}
|
||||
|
||||
// Process TTS injection points if enableAgentVibes option is provided
|
||||
let xml = result.xml;
|
||||
let ttsInjected = false;
|
||||
if (options.enableAgentVibes !== undefined) {
|
||||
const ttsResult = processTTSInjectionPoints(xml, options.enableAgentVibes);
|
||||
xml = ttsResult.content;
|
||||
ttsInjected = ttsResult.hadInjection;
|
||||
}
|
||||
|
||||
// Write compiled XML
|
||||
fs.writeFileSync(outputPath, xml, 'utf8');
|
||||
|
||||
|
|
@ -543,7 +505,6 @@ function compileAgentFile(yamlPath, options = {}) {
|
|||
xml,
|
||||
outputPath,
|
||||
sourcePath: yamlPath,
|
||||
ttsInjected,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ async function groupMultiselect(options) {
|
|||
options: options.options,
|
||||
initialValues: options.initialValues,
|
||||
required: options.required || false,
|
||||
selectableGroups: options.selectableGroups || false,
|
||||
});
|
||||
|
||||
await handleCancel(result);
|
||||
|
|
|
|||
|
|
@ -171,32 +171,6 @@ class UI {
|
|||
// Check if there's an existing BMAD installation (after any folder renames)
|
||||
const hasExistingInstall = await fs.pathExists(bmadDir);
|
||||
|
||||
// Collect IDE tool selection early - we need this to know if we should ask about TTS
|
||||
let toolSelection;
|
||||
let agentVibesConfig = { enabled: false, alreadyInstalled: false };
|
||||
let claudeCodeSelected = false;
|
||||
|
||||
if (!hasExistingInstall) {
|
||||
// For new installations, collect IDE selection first
|
||||
// We don't have modules yet, so pass empty array
|
||||
toolSelection = await this.promptToolSelection(confirmedDirectory, []);
|
||||
|
||||
// Check if Claude Code was selected
|
||||
claudeCodeSelected = toolSelection.ides && toolSelection.ides.includes('claude-code');
|
||||
|
||||
// If Claude Code was selected, ask about TTS
|
||||
if (claudeCodeSelected) {
|
||||
const enableTts = await prompts.confirm({
|
||||
message: 'Claude Code supports TTS (Text-to-Speech). Would you like to enable it?',
|
||||
default: false,
|
||||
});
|
||||
|
||||
if (enableTts) {
|
||||
agentVibesConfig = { enabled: true, alreadyInstalled: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let customContentConfig = { hasCustomContent: false };
|
||||
if (!hasExistingInstall) {
|
||||
customContentConfig._shouldAsk = true;
|
||||
|
|
@ -324,20 +298,8 @@ class UI {
|
|||
}
|
||||
|
||||
// Get tool selection
|
||||
const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
||||
const toolSelection = await this.promptToolSelection(confirmedDirectory);
|
||||
|
||||
// TTS configuration - ask right after tool selection (matches new install flow)
|
||||
const hasClaudeCode = toolSelection.ides && toolSelection.ides.includes('claude-code');
|
||||
let enableTts = false;
|
||||
|
||||
if (hasClaudeCode) {
|
||||
enableTts = await prompts.confirm({
|
||||
message: 'Claude Code supports TTS (Text-to-Speech). Would you like to enable it?',
|
||||
default: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Core config with existing defaults (ask after TTS)
|
||||
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
||||
|
||||
return {
|
||||
|
|
@ -349,8 +311,6 @@ class UI {
|
|||
skipIde: toolSelection.skipIde,
|
||||
coreConfig: coreConfig,
|
||||
customContent: customModuleResult.customContentConfig,
|
||||
enableAgentVibes: enableTts,
|
||||
agentVibesInstalled: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -372,7 +332,7 @@ class UI {
|
|||
|
||||
// Ask about custom content
|
||||
const wantsCustomContent = await prompts.confirm({
|
||||
message: 'Would you like to install a local custom module (this includes custom agents and workflows also)?',
|
||||
message: 'Would you like to install a locally stored custom module (this includes custom agents and workflows also)?',
|
||||
default: false,
|
||||
});
|
||||
|
||||
|
|
@ -391,19 +351,10 @@ class UI {
|
|||
selectedModules = [...selectedModules, ...customContentConfig.selectedModuleIds];
|
||||
}
|
||||
|
||||
// Remove core if it's in the list (it's always installed)
|
||||
selectedModules = selectedModules.filter((m) => m !== 'core');
|
||||
|
||||
// Tool selection (already done for new installs at the beginning)
|
||||
if (!toolSelection) {
|
||||
toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
||||
}
|
||||
|
||||
// Collect configurations for new installations
|
||||
let toolSelection = await this.promptToolSelection(confirmedDirectory);
|
||||
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
||||
|
||||
// TTS already handled at the beginning for new installs
|
||||
|
||||
return {
|
||||
actionType: 'install',
|
||||
directory: confirmedDirectory,
|
||||
|
|
@ -413,18 +364,15 @@ class UI {
|
|||
skipIde: toolSelection.skipIde,
|
||||
coreConfig: coreConfig,
|
||||
customContent: customContentConfig,
|
||||
enableAgentVibes: agentVibesConfig.enabled,
|
||||
agentVibesInstalled: agentVibesConfig.alreadyInstalled,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt for tool/IDE selection (called after module configuration)
|
||||
* @param {string} projectDir - Project directory to check for existing IDEs
|
||||
* @param {Array} selectedModules - Selected modules from configuration
|
||||
* @returns {Object} Tool configuration
|
||||
*/
|
||||
async promptToolSelection(projectDir, selectedModules) {
|
||||
async promptToolSelection(projectDir) {
|
||||
// Check for existing configured IDEs - use findBmadDir to detect custom folder names
|
||||
const { Detector } = require('../installers/lib/core/detector');
|
||||
const { Installer } = require('../installers/lib/core/installer');
|
||||
|
|
@ -447,7 +395,7 @@ class UI {
|
|||
const processedIdes = new Set();
|
||||
const initialValues = [];
|
||||
|
||||
// First, add previously configured IDEs at the top, marked with ✅
|
||||
// First, add previously configured IDEs, marked with ✅
|
||||
if (configuredIdes.length > 0) {
|
||||
const configuredGroup = [];
|
||||
for (const ideValue of configuredIdes) {
|
||||
|
|
@ -499,42 +447,33 @@ class UI {
|
|||
}));
|
||||
}
|
||||
|
||||
let selectedIdes = [];
|
||||
let userConfirmedNoTools = false;
|
||||
// Add standalone "None" option at the end
|
||||
groupedOptions[' '] = [
|
||||
{
|
||||
label: '⚠ None - I am not installing any tools',
|
||||
value: '__NONE__',
|
||||
},
|
||||
];
|
||||
|
||||
let selectedIdes = [];
|
||||
|
||||
// Loop until user selects at least one tool OR explicitly confirms no tools
|
||||
while (!userConfirmedNoTools) {
|
||||
selectedIdes = await prompts.groupMultiselect({
|
||||
message: `Select tools to configure ${chalk.dim('(↑/↓ navigate, SPACE select, ENTER confirm)')}:`,
|
||||
message: `Select tools to configure ${chalk.dim('(↑/↓ navigates multiselect, SPACE toggles, A to toggles All, ENTER confirm)')}:`,
|
||||
options: groupedOptions,
|
||||
initialValues: initialValues.length > 0 ? initialValues : undefined,
|
||||
required: false,
|
||||
required: true,
|
||||
selectableGroups: false,
|
||||
});
|
||||
|
||||
// If tools were selected, we're done
|
||||
if (selectedIdes && selectedIdes.length > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Warn that no tools were selected - users often miss the spacebar requirement
|
||||
// If user selected both "__NONE__" and other tools, honor the "None" choice
|
||||
if (selectedIdes && selectedIdes.includes('__NONE__') && selectedIdes.length > 1) {
|
||||
console.log();
|
||||
console.log(chalk.red.bold('⚠️ WARNING: No tools were selected!'));
|
||||
console.log(chalk.red(' You must press SPACE to select items, then ENTER to confirm.'));
|
||||
console.log(chalk.red(' Simply highlighting an item does NOT select it.'));
|
||||
console.log(chalk.yellow('⚠️ "None - I am not installing any tools" was selected, so no tools will be configured.'));
|
||||
console.log();
|
||||
|
||||
const goBack = await prompts.confirm({
|
||||
message: chalk.yellow('Would you like to go back and select at least one tool?'),
|
||||
default: true,
|
||||
});
|
||||
|
||||
if (goBack) {
|
||||
// Re-display a message before looping back
|
||||
console.log();
|
||||
} else {
|
||||
// User explicitly chose to proceed without tools
|
||||
userConfirmedNoTools = true;
|
||||
}
|
||||
selectedIdes = [];
|
||||
} else if (selectedIdes && selectedIdes.includes('__NONE__')) {
|
||||
// Only "__NONE__" was selected
|
||||
selectedIdes = [];
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -561,27 +500,6 @@ class UI {
|
|||
return { backupFirst, preserveCustomizations };
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt for module selection
|
||||
* @param {Array} modules - Available modules
|
||||
* @returns {Array} Selected modules
|
||||
*/
|
||||
async promptModules(modules) {
|
||||
const choices = modules.map((mod) => ({
|
||||
name: `${mod.name} - ${mod.description}`,
|
||||
value: mod.id,
|
||||
checked: false,
|
||||
}));
|
||||
|
||||
const selectedModules = await prompts.multiselect({
|
||||
message: `Select modules to add ${chalk.dim('(↑/↓ navigate, SPACE select, ENTER confirm)')}:`,
|
||||
choices,
|
||||
required: true,
|
||||
});
|
||||
|
||||
return selectedModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm action
|
||||
* @param {string} message - Confirmation message
|
||||
|
|
@ -608,25 +526,6 @@ class UI {
|
|||
if (result.modules && result.modules.length > 0) {
|
||||
console.log(chalk.dim(`Modules: ${result.modules.join(', ')}`));
|
||||
}
|
||||
if (result.agentVibesEnabled) {
|
||||
console.log(chalk.dim(`TTS: Enabled`));
|
||||
}
|
||||
|
||||
// TTS injection info (simplified)
|
||||
if (result.ttsInjectedFiles && result.ttsInjectedFiles.length > 0) {
|
||||
console.log(chalk.dim(`\n💡 TTS enabled for ${result.ttsInjectedFiles.length} agent(s)`));
|
||||
console.log(chalk.dim(' Agents will now speak when using AgentVibes'));
|
||||
}
|
||||
|
||||
console.log(chalk.yellow('\nThank you for helping test the early release version of the new BMad Core and BMad Method!'));
|
||||
console.log(chalk.cyan('Stable Beta coming soon - please read the full README.md and linked documentation to get started!'));
|
||||
|
||||
// Add changelog link at the end
|
||||
console.log(
|
||||
chalk.magenta(
|
||||
"\n📋 Want to see what's new? Check out the changelog: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -768,20 +667,40 @@ class UI {
|
|||
* @param {Array} moduleChoices - Available module choices
|
||||
* @returns {Array} Selected module IDs
|
||||
*/
|
||||
async selectModules(moduleChoices, defaultSelections = []) {
|
||||
// Mark choices as checked based on defaultSelections
|
||||
async selectModules(moduleChoices, defaultSelections = null) {
|
||||
// If defaultSelections is provided, use it to override checked state
|
||||
// Otherwise preserve the checked state from moduleChoices (set by getModuleChoices)
|
||||
const choicesWithDefaults = moduleChoices.map((choice) => ({
|
||||
...choice,
|
||||
checked: defaultSelections.includes(choice.value),
|
||||
...(defaultSelections === null ? {} : { checked: defaultSelections.includes(choice.value) }),
|
||||
}));
|
||||
|
||||
// Add a "None" option at the end for users who changed their mind
|
||||
const choicesWithSkipOption = [
|
||||
...choicesWithDefaults,
|
||||
{
|
||||
value: '__NONE__',
|
||||
label: '⚠ None / I changed my mind - skip module installation',
|
||||
checked: false,
|
||||
},
|
||||
];
|
||||
|
||||
const selected = await prompts.multiselect({
|
||||
message: `Select modules to install ${chalk.dim('(↑/↓ navigate, SPACE select, ENTER confirm)')}:`,
|
||||
choices: choicesWithDefaults,
|
||||
required: false,
|
||||
message: `Select modules to install ${chalk.dim('(↑/↓ navigates multiselect, SPACE toggles, A to toggles All, ENTER confirm)')}:`,
|
||||
choices: choicesWithSkipOption,
|
||||
required: true,
|
||||
});
|
||||
|
||||
return selected || [];
|
||||
// If user selected both "__NONE__" and other items, honor the "None" choice
|
||||
if (selected && selected.includes('__NONE__') && selected.length > 1) {
|
||||
console.log();
|
||||
console.log(chalk.yellow('⚠️ "None / I changed my mind" was selected, so no modules will be installed.'));
|
||||
console.log();
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter out the special '__NONE__' value
|
||||
return selected ? selected.filter((m) => m !== '__NONE__') : [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1061,136 +980,6 @@ class UI {
|
|||
return path.resolve(expanded);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function promptAgentVibes
|
||||
* @intent Ask user if they want AgentVibes TTS integration during BMAD installation
|
||||
* @why Enables optional voice features without forcing TTS on users who don't want it
|
||||
* @param {string} projectDir - Absolute path to user's project directory
|
||||
* @returns {Promise<Object>} Configuration object: { enabled: boolean, alreadyInstalled: boolean }
|
||||
* @sideeffects None - pure user input collection, no files written
|
||||
* @edgecases Shows warning if user enables TTS but AgentVibes not detected
|
||||
* @calledby promptInstall() during installation flow, after core config, before IDE selection
|
||||
* @calls checkAgentVibesInstalled(), prompts.select(), chalk.green/yellow/dim()
|
||||
*
|
||||
* AI NOTE: This prompt is strategically positioned in installation flow:
|
||||
* - AFTER core config (user_name, etc)
|
||||
* - BEFORE IDE selection (which can hang on Windows/PowerShell)
|
||||
*
|
||||
* Flow Logic:
|
||||
* 1. Auto-detect if AgentVibes already installed (checks for hook files)
|
||||
* 2. Show detection status to user (green checkmark or gray "not detected")
|
||||
* 3. Prompt: "Enable AgentVibes TTS?" (defaults to true if detected)
|
||||
* 4. If user says YES but AgentVibes NOT installed:
|
||||
* → Show warning with installation link (graceful degradation)
|
||||
* 5. Return config to promptInstall(), which passes to installer.install()
|
||||
*
|
||||
* State Flow:
|
||||
* promptAgentVibes() → { enabled, alreadyInstalled }
|
||||
* ↓
|
||||
* promptInstall() → config.enableAgentVibes
|
||||
* ↓
|
||||
* installer.install() → this.enableAgentVibes
|
||||
* ↓
|
||||
* processTTSInjectionPoints() → injects OR strips markers
|
||||
*
|
||||
* RELATED:
|
||||
* ========
|
||||
* - Detection: checkAgentVibesInstalled() - looks for bmad-speak.sh and play-tts.sh
|
||||
* - Processing: installer.js::processTTSInjectionPoints()
|
||||
* - Markers: src/core/workflows/party-mode/instructions.md:101, src/modules/bmm/agents/*.md
|
||||
* - GitHub Issue: paulpreibisch/AgentVibes#36
|
||||
*/
|
||||
async promptAgentVibes(projectDir) {
|
||||
CLIUtils.displaySection('🎤 Voice Features', 'Enable TTS for multi-agent conversations');
|
||||
|
||||
// Check if AgentVibes is already installed
|
||||
const agentVibesInstalled = await this.checkAgentVibesInstalled(projectDir);
|
||||
|
||||
if (agentVibesInstalled) {
|
||||
console.log(chalk.green(' ✓ AgentVibes detected'));
|
||||
} else {
|
||||
console.log(chalk.dim(' AgentVibes not detected'));
|
||||
}
|
||||
|
||||
const enableTts = await prompts.confirm({
|
||||
message: 'Enable Agents to Speak Out loud (powered by Agent Vibes? Claude Code only currently)',
|
||||
default: false,
|
||||
});
|
||||
|
||||
if (enableTts && !agentVibesInstalled) {
|
||||
console.log(chalk.yellow('\n ⚠️ AgentVibes not installed'));
|
||||
console.log(chalk.dim(' Install AgentVibes separately to enable TTS:'));
|
||||
console.log(chalk.dim(' https://github.com/paulpreibisch/AgentVibes\n'));
|
||||
}
|
||||
|
||||
return {
|
||||
enabled: enableTts,
|
||||
alreadyInstalled: agentVibesInstalled,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @function checkAgentVibesInstalled
|
||||
* @intent Detect if AgentVibes TTS hooks are present in user's project
|
||||
* @why Allows auto-enabling TTS and showing helpful installation guidance
|
||||
* @param {string} projectDir - Absolute path to user's project directory
|
||||
* @returns {Promise<boolean>} true if both required AgentVibes hooks exist, false otherwise
|
||||
* @sideeffects None - read-only file existence checks
|
||||
* @edgecases Returns false if either hook missing (both required for functional TTS)
|
||||
* @calledby promptAgentVibes() to determine default value and show detection status
|
||||
* @calls fs.pathExists() twice (bmad-speak.sh, play-tts.sh)
|
||||
*
|
||||
* AI NOTE: This checks for the MINIMUM viable AgentVibes installation.
|
||||
*
|
||||
* Required Files:
|
||||
* ===============
|
||||
* 1. .claude/hooks/bmad-speak.sh
|
||||
* - Maps agent display names → agent IDs → voice profiles
|
||||
* - Calls play-tts.sh with agent's assigned voice
|
||||
* - Created by AgentVibes installer
|
||||
*
|
||||
* 2. .claude/hooks/play-tts.sh
|
||||
* - Core TTS router (ElevenLabs or Piper)
|
||||
* - Provider-agnostic interface
|
||||
* - Required by bmad-speak.sh
|
||||
*
|
||||
* Why Both Required:
|
||||
* ==================
|
||||
* - bmad-speak.sh alone: No TTS backend
|
||||
* - play-tts.sh alone: No BMAD agent voice mapping
|
||||
* - Both together: Full party mode TTS integration
|
||||
*
|
||||
* Detection Strategy:
|
||||
* ===================
|
||||
* We use simple file existence (not version checks) because:
|
||||
* - Fast and reliable
|
||||
* - Works across all AgentVibes versions
|
||||
* - User will discover version issues when TTS runs (fail-fast)
|
||||
*
|
||||
* PATTERN: Adding New Detection Criteria
|
||||
* =======================================
|
||||
* If future AgentVibes features require additional files:
|
||||
* 1. Add new pathExists check to this function
|
||||
* 2. Update documentation in promptAgentVibes()
|
||||
* 3. Consider: should missing file prevent detection or just log warning?
|
||||
*
|
||||
* RELATED:
|
||||
* ========
|
||||
* - AgentVibes Installer: creates these hooks
|
||||
* - bmad-speak.sh: calls play-tts.sh with agent voices
|
||||
* - Party Mode: uses bmad-speak.sh for agent dialogue
|
||||
*/
|
||||
async checkAgentVibesInstalled(projectDir) {
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
|
||||
// Check for AgentVibes hook files
|
||||
const hookPath = path.join(projectDir, '.claude', 'hooks', 'bmad-speak.sh');
|
||||
const playTtsPath = path.join(projectDir, '.claude', 'hooks', 'play-tts.sh');
|
||||
|
||||
return (await fs.pathExists(hookPath)) && (await fs.pathExists(playTtsPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load existing configurations to use as defaults
|
||||
* @param {string} directory - Installation directory
|
||||
|
|
@ -1201,7 +990,6 @@ class UI {
|
|||
hasCustomContent: false,
|
||||
coreConfig: {},
|
||||
ideConfig: { ides: [], skipIde: false },
|
||||
agentVibesConfig: { enabled: false, alreadyInstalled: false },
|
||||
};
|
||||
|
||||
try {
|
||||
|
|
@ -1215,10 +1003,6 @@ class UI {
|
|||
configs.ideConfig.skipIde = false;
|
||||
}
|
||||
|
||||
// Load AgentVibes configuration
|
||||
const agentVibesInstalled = await this.checkAgentVibesInstalled(directory);
|
||||
configs.agentVibesConfig = { enabled: agentVibesInstalled, alreadyInstalled: agentVibesInstalled };
|
||||
|
||||
return configs;
|
||||
} catch {
|
||||
// If loading fails, return empty configs
|
||||
|
|
@ -1461,12 +1245,32 @@ class UI {
|
|||
checked: m.checked,
|
||||
}));
|
||||
|
||||
// Add "None / I changed my mind" option at the end
|
||||
const choicesWithSkip = [
|
||||
...selectChoices,
|
||||
{
|
||||
name: '⚠ None / I changed my mind - keep no custom modules',
|
||||
value: '__NONE__',
|
||||
checked: false,
|
||||
},
|
||||
];
|
||||
|
||||
const keepModules = await prompts.multiselect({
|
||||
message: `Select custom modules to keep ${chalk.dim('(↑/↓ navigate, SPACE select, ENTER confirm)')}:`,
|
||||
choices: selectChoices,
|
||||
required: false,
|
||||
message: `Select custom modules to keep ${chalk.dim('(↑/↓ navigates multiselect, SPACE toggles, A to toggles All, ENTER confirm)')}:`,
|
||||
choices: choicesWithSkip,
|
||||
required: true,
|
||||
});
|
||||
result.selectedCustomModules = keepModules || [];
|
||||
|
||||
// If user selected both "__NONE__" and other modules, honor the "None" choice
|
||||
if (keepModules && keepModules.includes('__NONE__') && keepModules.length > 1) {
|
||||
console.log();
|
||||
console.log(chalk.yellow('⚠️ "None / I changed my mind" was selected, so no custom modules will be kept.'));
|
||||
console.log();
|
||||
result.selectedCustomModules = [];
|
||||
} else {
|
||||
// Filter out the special '__NONE__' value
|
||||
result.selectedCustomModules = keepModules ? keepModules.filter((m) => m !== '__NONE__') : [];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue