Merge branch 'main' into feature/more-cynical-review

This commit is contained in:
Brian 2025-12-18 16:19:25 +08:00 committed by GitHub
commit af5e1c929d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 1040 additions and 3695 deletions

View File

@ -1,5 +1,25 @@
# Changelog
## [6.0.0-alpha.19]
**Release: December 18, 2025**
### 🐛 Bug Fixes
**Installer Stability:**
- **Fixed \_bmad Folder Stutter**: Resolved issue with duplicate \_bmad folder creation when applying agent custom files
- **Cleaner Installation**: Removed unnecessary backup file that was causing bloat in the installer
- **Streamlined Agent Customization**: Fixed path handling for agent custom files to prevent folder duplication
### 📊 Statistics
- **3 files changed** with critical fix
- **3,688 lines removed** by eliminating backup files
- **Improved installer performance** and stability
---
## [6.0.0-alpha.18]
**Release: December 18, 2025**

View File

@ -231,6 +231,8 @@ MIT License - See [LICENSE](LICENSE) for details.
**Trademarks:** BMad™ and BMAD-METHOD™ are trademarks of BMad Code, LLC.
Supported by:&nbsp;&nbsp;<a href="https://m.do.co/c/00f11bd932bb"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="24" alt="DigitalOcean" style="vertical-align: middle;"></a>
---
<p align="center">

View File

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "bmad-method",
"version": "6.0.0-alpha.18",
"version": "6.0.0-alpha.19",
"description": "Breakthrough Method of Agile AI-driven Development",
"keywords": [
"agile",

View File

@ -33,6 +33,10 @@ agent:
exec: "{project-root}/_bmad/bmgd/workflows/3-technical/game-architecture/workflow.md"
description: Produce a Scale Adaptive Game Architecture
- trigger: generate-project-context
exec: "{project-root}/_bmad/bmgd/workflows/3-technical/generate-project-context/workflow.md"
description: Create optimized project-context.md for AI agent consistency
- trigger: correct-course
workflow: "{project-root}/_bmad/bmgd/workflows/4-production/correct-course/workflow.yaml"
description: Course Correction Analysis (when implementation is off-track)

View File

@ -12,6 +12,7 @@ outputFile: '{output_folder}/game-architecture.md'
# Handoff References
epicWorkflow: '{project-root}/_bmad/bmgd/workflows/4-production/epic-workflow/workflow.yaml'
projectContextWorkflow: '{project-root}/_bmad/bmgd/workflows/3-technical/generate-project-context/workflow.md'
---
# Step 9: Completion
@ -131,7 +132,17 @@ platform: '{{platform}}'
---
````
### 4. Present Completion Summary
### 4. Update Workflow Status
**If not in standalone mode:**
Load `{output_folder}/bmgd-workflow-status.yaml` and:
- Update `create-architecture` status to the output file path
- Preserve all comments and structure
- Determine next workflow in sequence
### 5. Present Completion Summary
"**Architecture Complete!**
@ -158,9 +169,50 @@ platform: '{{platform}}'
**Document saved to:** `{outputFile}`
Do you want to review or adjust anything before we finalize?"
Do you want to review or adjust anything before we finalize?
### 5. Handle Review Requests
**Optional Enhancement: Project Context File**
Would you like to create a `project-context.md` file? This is a concise, optimized guide for AI agents that captures:
- Critical engine-specific rules they might miss
- Specific patterns and conventions for your game project
- Performance and optimization requirements
- Anti-patterns and edge cases to avoid
{if_existing_project_context}
I noticed you already have a project context file. Would you like to update it with your new architectural decisions?
{else}
This file helps ensure AI agents implement game code consistently with your project's unique requirements and patterns.
{/if_existing_project_context}
**Create/Update project context?** [Y/N]"
### 6. Handle Project Context Creation Choice
If user responds 'Y' or 'yes' to creating/updating project context:
"Excellent choice! Let me launch the Generate Project Context workflow to create a comprehensive guide for AI agents.
This will help ensure consistent implementation by capturing:
- Engine-specific patterns and rules
- Performance and optimization conventions from your architecture
- Testing and quality standards
- Anti-patterns to avoid
The workflow will collaborate with you to create an optimized `project-context.md` file that AI agents will read before implementing any game code."
**Execute the Generate Project Context workflow:**
- Load and execute: `{projectContextWorkflow}`
- The workflow will handle discovery, generation, and completion of the project context file
- After completion, return here for final handoff
If user responds 'N' or 'no':
"Understood! Your architecture is complete and ready for implementation. You can always create a project context file later using the Generate Project Context workflow if needed."
### 7. Handle Review Requests
**If user wants to review:**
@ -179,7 +231,7 @@ Or type 'all' to see the complete document."
**Show requested section and allow edits.**
### 6. Present Next Steps Menu
### 8. Present Next Steps Menu
**After user confirms completion:**
@ -204,7 +256,7 @@ Or type 'all' to see the complete document."
2. Proceed to Epic creation workflow
3. Exit workflow"
### 7. Handle User Selection
### 9. Handle User Selection
Based on user choice:
@ -224,7 +276,7 @@ Based on user choice:
- Confirm document is saved and complete
- Exit workflow gracefully
### 8. Provide Handoff Guidance
### 10. Provide Handoff Guidance
**For Epic Creation handoff:**
@ -270,6 +322,7 @@ This is the final step. Ensure:
- Development setup is complete
- Document status updated to 'complete'
- Frontmatter shows all steps completed
- Workflow status updated (if tracking)
- User has clear next steps
- Document saved and ready for AI agent consumption
@ -278,6 +331,7 @@ This is the final step. Ensure:
- Missing executive summary
- Incomplete development setup
- Frontmatter not updated
- Status not updated when tracking
- No clear next steps provided
- User left without actionable guidance

View File

@ -0,0 +1,20 @@
---
project_name: '{{project_name}}'
user_name: '{{user_name}}'
date: '{{date}}'
sections_completed: []
---
# Project Context for AI Agents
_This file contains critical rules and patterns that AI agents must follow when implementing game code in this project. Focus on unobvious details that agents might otherwise miss._
---
## Technology Stack & Versions
_Documented after discovery phase_
## Critical Implementation Rules
_Documented after discovery phase_

View File

@ -0,0 +1,201 @@
# Step 1: Context Discovery & Initialization
## MANDATORY EXECUTION RULES (READ FIRST):
- NEVER generate content without user input
- ALWAYS treat this as collaborative discovery between technical peers
- YOU ARE A FACILITATOR, not a content generator
- FOCUS on discovering existing project context and technology stack
- IDENTIFY critical implementation rules that AI agents need
- ABSOLUTELY NO TIME ESTIMATES
## EXECUTION PROTOCOLS:
- Show your analysis before taking any action
- Read existing project files to understand current context
- Initialize document and update frontmatter
- FORBIDDEN to load next step until discovery is complete
## CONTEXT BOUNDARIES:
- Variables from workflow.md are available in memory
- Focus on existing project files and architecture decisions
- Look for patterns, conventions, and unique requirements
- Prioritize rules that prevent implementation mistakes
## YOUR TASK:
Discover the project's game engine, technology stack, existing patterns, and critical implementation rules that AI agents must follow when writing game code.
## DISCOVERY SEQUENCE:
### 1. Check for Existing Project Context
First, check if project context already exists:
- Look for file at `{output_folder}/project-context.md`
- If exists: Read complete file to understand existing rules
- Present to user: "Found existing project context with {number_of_sections} sections. Would you like to update this or create a new one?"
### 2. Discover Game Engine & Technology Stack
Load and analyze project files to identify technologies:
**Architecture Document:**
- Look for `{output_folder}/game-architecture.md` or `{output_folder}/architecture.md`
- Extract engine choice with specific version (Unity, Unreal, Godot, custom)
- Note architectural decisions that affect implementation
**Engine-Specific Files:**
- Unity: Check for `ProjectSettings/ProjectVersion.txt`, `Packages/manifest.json`
- Unreal: Check for `.uproject` files, `Config/DefaultEngine.ini`
- Godot: Check for `project.godot`, `export_presets.cfg`
- Custom: Check for engine config files, build scripts
**Package/Dependency Files:**
- Unity: `Packages/manifest.json`, NuGet packages
- Unreal: `.Build.cs` files, plugin configs
- Godot: `addons/` directory, GDExtension configs
- Web-based: `package.json`, `requirements.txt`
**Configuration Files:**
- Build tool configs
- Linting and formatting configs
- Testing configurations
- CI/CD pipeline configs
### 3. Identify Existing Code Patterns
Search through existing codebase for patterns:
**Naming Conventions:**
- Script/class naming patterns
- Asset naming conventions
- Scene/level naming patterns
- Test file naming patterns
**Code Organization:**
- How components/scripts are structured
- Where utilities and helpers are placed
- How systems are organized
- Folder hierarchy patterns
**Engine-Specific Patterns:**
- Unity: MonoBehaviour patterns, ScriptableObject usage, serialization rules
- Unreal: Actor/Component patterns, Blueprint integration, UE macros
- Godot: Node patterns, signal usage, autoload patterns
### 4. Extract Critical Implementation Rules
Look for rules that AI agents might miss:
**Engine-Specific Rules:**
- Unity: Assembly definitions, Unity lifecycle methods, coroutine patterns
- Unreal: UPROPERTY/UFUNCTION usage, garbage collection rules, tick patterns
- Godot: `_ready` vs `_enter_tree`, node ownership, scene instancing
**Performance Rules:**
- Frame budget constraints
- Memory allocation patterns
- Hot path optimization requirements
- Object pooling patterns
**Platform-Specific Rules:**
- Target platform constraints
- Input handling conventions
- Platform-specific code patterns
- Build configuration rules
**Testing Rules:**
- Test structure requirements
- Mock usage conventions
- Integration vs unit test boundaries
- Play mode vs edit mode testing
### 5. Initialize Project Context Document
Based on discovery, create or update the context document:
#### A. Fresh Document Setup (if no existing context)
Copy template from `{installed_path}/project-context-template.md` to `{output_folder}/project-context.md`
Initialize frontmatter with:
```yaml
---
project_name: '{{project_name}}'
user_name: '{{user_name}}'
date: '{{date}}'
sections_completed: ['technology_stack']
existing_patterns_found: { { number_of_patterns_discovered } }
---
```
#### B. Existing Document Update
Load existing context and prepare for updates
Set frontmatter `sections_completed` to track what will be updated
### 6. Present Discovery Summary
Report findings to user:
"Welcome {{user_name}}! I've analyzed your game project for {{project_name}} to discover the context that AI agents need.
**Game Engine & Stack Discovered:**
{{engine_and_version}}
{{list_of_technologies_with_versions}}
**Existing Patterns Found:**
- {{number_of_patterns}} implementation patterns
- {{number_of_conventions}} coding conventions
- {{number_of_rules}} critical rules
**Key Areas for Context Rules:**
- {{area_1}} (e.g., Engine lifecycle and patterns)
- {{area_2}} (e.g., Performance and optimization)
- {{area_3}} (e.g., Platform-specific requirements)
{if_existing_context}
**Existing Context:** Found {{sections}} sections already defined. We can update or add to these.
{/if_existing_context}
Ready to create/update your project context. This will help AI agents implement game code consistently with your project's standards.
[C] Continue to context generation"
## SUCCESS METRICS:
- Existing project context properly detected and handled
- Game engine and technology stack accurately identified with versions
- Critical implementation patterns discovered
- Project context document properly initialized
- Discovery findings clearly presented to user
- User ready to proceed with context generation
## FAILURE MODES:
- Not checking for existing project context before creating new one
- Missing critical engine versions or configurations
- Overlooking important coding patterns or conventions
- Not initializing frontmatter properly
- Not presenting clear discovery summary to user
## NEXT STEP:
After user selects [C] to continue, load `./step-02-generate.md` to collaboratively generate the specific project context rules.
Remember: Do NOT proceed to step-02 until user explicitly selects [C] from the menu and discovery is confirmed!

View File

@ -0,0 +1,373 @@
# Step 2: Context Rules Generation
## MANDATORY EXECUTION RULES (READ FIRST):
- NEVER generate content without user input
- ALWAYS treat this as collaborative discovery between technical peers
- YOU ARE A FACILITATOR, not a content generator
- FOCUS on unobvious rules that AI agents need to be reminded of
- KEEP CONTENT LEAN - optimize for LLM context efficiency
- ABSOLUTELY NO TIME ESTIMATES
## EXECUTION PROTOCOLS:
- Show your analysis before taking any action
- Focus on specific, actionable rules rather than general advice
- Present A/P/C menu after each major rule category
- ONLY save when user chooses C (Continue)
- Update frontmatter with completed sections
- FORBIDDEN to load next step until all sections are complete
## COLLABORATION MENUS (A/P/C):
This step will generate content and present choices for each rule category:
- **A (Advanced Elicitation)**: Use discovery protocols to explore nuanced implementation rules
- **P (Party Mode)**: Bring multiple perspectives to identify critical edge cases
- **C (Continue)**: Save the current rules and proceed to next category
## PROTOCOL INTEGRATION:
- When 'A' selected: Execute {project-root}/\_bmad/core/tasks/advanced-elicitation.xml
- When 'P' selected: Execute {project-root}/\_bmad/core/workflows/party-mode
- PROTOCOLS always return to display this step's A/P/C menu after the A or P have completed
- User accepts/rejects protocol changes before proceeding
## CONTEXT BOUNDARIES:
- Discovery results from step-1 are available
- Game engine and existing patterns are identified
- Focus on rules that prevent implementation mistakes
- Prioritize unobvious details that AI agents might miss
## YOUR TASK:
Collaboratively generate specific, critical rules that AI agents must follow when implementing game code in this project.
## CONTEXT GENERATION SEQUENCE:
### 1. Technology Stack & Versions
Document the exact technology stack from discovery:
**Core Technologies:**
Based on user skill level, present findings:
**Expert Mode:**
"Technology stack from your architecture and project files:
{{exact_technologies_with_versions}}
Any critical version constraints I should document for agents?"
**Intermediate Mode:**
"I found your technology stack:
**Game Engine:**
{{engine_with_version}}
**Key Dependencies:**
{{important_dependencies_with_versions}}
Are there any version constraints or compatibility notes agents should know about?"
**Beginner Mode:**
"Here are the technologies you're using:
**Game Engine:**
{{friendly_description_of_engine}}
**Important Notes:**
{{key_things_agents_need_to_know_about_versions}}
Should I document any special version rules or compatibility requirements?"
### 2. Engine-Specific Rules
Focus on unobvious engine patterns agents might miss:
**Unity Rules (if applicable):**
"Based on your Unity project, I notice some specific patterns:
**Lifecycle Rules:**
{{unity_lifecycle_patterns}}
**Serialization Rules:**
{{serialization_requirements}}
**Assembly Definitions:**
{{assembly_definition_rules}}
**Coroutine/Async Patterns:**
{{async_patterns}}
Are these patterns correct? Any other Unity-specific rules agents should follow?"
**Unreal Rules (if applicable):**
"Based on your Unreal project, I notice some specific patterns:
**UPROPERTY/UFUNCTION Rules:**
{{macro_usage_patterns}}
**Blueprint Integration:**
{{blueprint_rules}}
**Garbage Collection:**
{{gc_patterns}}
**Tick Patterns:**
{{tick_optimization_rules}}
Are these patterns correct? Any other Unreal-specific rules agents should follow?"
**Godot Rules (if applicable):**
"Based on your Godot project, I notice some specific patterns:
**Node Lifecycle:**
{{node_lifecycle_patterns}}
**Signal Usage:**
{{signal_conventions}}
**Scene Instancing:**
{{scene_patterns}}
**Autoload Patterns:**
{{autoload_rules}}
Are these patterns correct? Any other Godot-specific rules agents should follow?"
### 3. Performance Rules
Document performance-critical patterns:
**Frame Budget Rules:**
"Your game has these performance requirements:
**Target Frame Rate:**
{{target_fps}}
**Frame Budget:**
{{milliseconds_per_frame}}
**Critical Systems:**
{{systems_that_must_meet_budget}}
**Hot Path Rules:**
{{hot_path_patterns}}
Any other performance rules agents must follow?"
**Memory Management:**
"Memory patterns for your project:
**Allocation Rules:**
{{allocation_patterns}}
**Pooling Requirements:**
{{object_pooling_rules}}
**Asset Loading:**
{{asset_loading_patterns}}
Are there memory constraints agents should know about?"
### 4. Code Organization Rules
Document project structure and organization:
**Folder Structure:**
"Your project organization:
**Script Organization:**
{{script_folder_structure}}
**Asset Organization:**
{{asset_folder_patterns}}
**Scene/Level Organization:**
{{scene_organization}}
Any organization rules agents must follow?"
**Naming Conventions:**
"Your naming patterns:
**Script/Class Names:**
{{class_naming_patterns}}
**Asset Names:**
{{asset_naming_patterns}}
**Variable/Method Names:**
{{variable_naming_patterns}}
Any other naming rules?"
### 5. Testing Rules
Focus on testing patterns that ensure consistency:
**Test Structure Rules:**
"Your testing setup shows these patterns:
**Test Organization:**
{{test_file_organization}}
**Test Categories:**
{{unit_vs_integration_boundaries}}
**Mocking Patterns:**
{{mock_usage_conventions}}
**Play Mode Testing:**
{{play_mode_test_patterns}}
Are there testing rules agents should always follow?"
### 6. Platform & Build Rules
Document platform-specific requirements:
**Target Platforms:**
"Your platform configuration:
**Primary Platform:**
{{primary_platform}}
**Platform-Specific Code:**
{{platform_conditional_patterns}}
**Build Configurations:**
{{build_config_rules}}
**Input Handling:**
{{input_abstraction_patterns}}
Any platform rules agents must know?"
### 7. Critical Don't-Miss Rules
Identify rules that prevent common mistakes:
**Anti-Patterns to Avoid:**
"Based on your codebase, here are critical things agents must NOT do:
{{critical_anti_patterns_with_examples}}
**Edge Cases:**
{{specific_edge_cases_agents_should_handle}}
**Common Gotchas:**
{{engine_specific_gotchas}}
**Performance Traps:**
{{performance_patterns_to_avoid}}
Are there other 'gotchas' agents should know about?"
### 8. Generate Context Content
For each category, prepare lean content for the project context file:
#### Content Structure:
```markdown
## Technology Stack & Versions
{{concise_technology_list_with_exact_versions}}
## Critical Implementation Rules
### Engine-Specific Rules
{{bullet_points_of_engine_rules}}
### Performance Rules
{{bullet_points_of_performance_requirements}}
### Code Organization Rules
{{bullet_points_of_organization_patterns}}
### Testing Rules
{{bullet_points_of_testing_requirements}}
### Platform & Build Rules
{{bullet_points_of_platform_requirements}}
### Critical Don't-Miss Rules
{{bullet_points_of_anti_patterns_and_gotchas}}
```
### 9. Present Content and Menu
After each category, show the generated rules and present choices:
"I've drafted the {{category_name}} rules for your project context.
**Here's what I'll add:**
[Show the complete markdown content for this category]
**What would you like to do?**
[A] Advanced Elicitation - Explore nuanced rules for this category
[P] Party Mode - Review from different implementation perspectives
[C] Continue - Save these rules and move to next category"
### 10. Handle Menu Selection
#### If 'A' (Advanced Elicitation):
- Execute advanced-elicitation.xml with current category rules
- Process enhanced rules that come back
- Ask user: "Accept these enhanced rules for {{category}}? (y/n)"
- If yes: Update content, then return to A/P/C menu
- If no: Keep original content, then return to A/P/C menu
#### If 'P' (Party Mode):
- Execute party-mode workflow with category rules context
- Process collaborative insights on implementation patterns
- Ask user: "Accept these changes to {{category}} rules? (y/n)"
- If yes: Update content, then return to A/P/C menu
- If no: Keep original content, then return to A/P/C menu
#### If 'C' (Continue):
- Save the current category content to project context file
- Update frontmatter: `sections_completed: [...]`
- Proceed to next category or step-03 if complete
## APPEND TO PROJECT CONTEXT:
When user selects 'C' for a category, append the content directly to `{output_folder}/project-context.md` using the structure from step 8.
## SUCCESS METRICS:
- All critical technology versions accurately documented
- Engine-specific rules cover unobvious patterns
- Performance rules capture project-specific requirements
- Code organization rules maintain project standards
- Testing rules ensure consistent test quality
- Platform rules prevent cross-platform issues
- Content is lean and optimized for LLM context
- A/P/C menu presented and handled correctly for each category
## FAILURE MODES:
- Including obvious rules that agents already know
- Making content too verbose for LLM context efficiency
- Missing critical anti-patterns or edge cases
- Not getting user validation for each rule category
- Not documenting exact versions and configurations
- Not presenting A/P/C menu after content generation
## NEXT STEP:
After completing all rule categories and user selects 'C' for the final category, load `./step-03-complete.md` to finalize the project context file.
Remember: Do NOT proceed to step-03 until all categories are complete and user explicitly selects 'C' for each!

View File

@ -0,0 +1,279 @@
# Step 3: Context Completion & Finalization
## MANDATORY EXECUTION RULES (READ FIRST):
- NEVER generate content without user input
- ALWAYS treat this as collaborative completion between technical peers
- YOU ARE A FACILITATOR, not a content generator
- FOCUS on finalizing a lean, LLM-optimized project context
- ENSURE all critical rules are captured and actionable
- ABSOLUTELY NO TIME ESTIMATES
## EXECUTION PROTOCOLS:
- Show your analysis before taking any action
- Review and optimize content for LLM context efficiency
- Update frontmatter with completion status
- NO MORE STEPS - this is the final step
## CONTEXT BOUNDARIES:
- All rule categories from step-2 are complete
- Technology stack and versions are documented
- Focus on final review, optimization, and completion
- Ensure the context file is ready for AI agent consumption
## YOUR TASK:
Complete the project context file, optimize it for LLM efficiency, and provide guidance for usage and maintenance.
## COMPLETION SEQUENCE:
### 1. Review Complete Context File
Read the entire project context file and analyze:
**Content Analysis:**
- Total length and readability for LLMs
- Clarity and specificity of rules
- Coverage of all critical areas
- Actionability of each rule
**Structure Analysis:**
- Logical organization of sections
- Consistency of formatting
- Absence of redundant or obvious information
- Optimization for quick scanning
### 2. Optimize for LLM Context
Ensure the file is lean and efficient:
**Content Optimization:**
- Remove any redundant rules or obvious information
- Combine related rules into concise bullet points
- Use specific, actionable language
- Ensure each rule provides unique value
**Formatting Optimization:**
- Use consistent markdown formatting
- Implement clear section hierarchy
- Ensure scannability with strategic use of bolding
- Maintain readability while maximizing information density
### 3. Final Content Structure
Ensure the final structure follows this optimized format:
```markdown
# Project Context for AI Agents
_This file contains critical rules and patterns that AI agents must follow when implementing game code in this project. Focus on unobvious details that agents might otherwise miss._
---
## Technology Stack & Versions
{{concise_technology_list}}
## Critical Implementation Rules
### Engine-Specific Rules
{{engine_rules}}
### Performance Rules
{{performance_requirements}}
### Code Organization Rules
{{organization_patterns}}
### Testing Rules
{{testing_requirements}}
### Platform & Build Rules
{{platform_requirements}}
### Critical Don't-Miss Rules
{{anti_patterns_and_gotchas}}
---
## Usage Guidelines
**For AI Agents:**
- Read this file before implementing any game code
- Follow ALL rules exactly as documented
- When in doubt, prefer the more restrictive option
- Update this file if new patterns emerge
**For Humans:**
- Keep this file lean and focused on agent needs
- Update when technology stack changes
- Review quarterly for outdated rules
- Remove rules that become obvious over time
Last Updated: {{date}}
```
### 4. Present Completion Summary
Based on user skill level, present the completion:
**Expert Mode:**
"Project context complete. Optimized for LLM consumption with {{rule_count}} critical rules across {{section_count}} sections.
File saved to: `{output_folder}/project-context.md`
Ready for AI agent integration."
**Intermediate Mode:**
"Your project context is complete and optimized for AI agents!
**What we created:**
- {{rule_count}} critical implementation rules
- Technology stack with exact versions
- Engine-specific patterns and conventions
- Performance and optimization guidelines
- Testing and platform requirements
**Key benefits:**
- AI agents will implement consistently with your standards
- Reduced context switching and implementation errors
- Clear guidance for unobvious project requirements
**Next steps:**
- AI agents should read this file before implementing
- Update as your project evolves
- Review periodically for optimization"
**Beginner Mode:**
"Excellent! Your project context guide is ready!
**What this does:**
Think of this as a 'rules of the road' guide for AI agents working on your game. It ensures they all follow the same patterns and avoid common mistakes.
**What's included:**
- Exact engine and technology versions to use
- Critical coding rules they might miss
- Performance and optimization standards
- Testing and platform requirements
**How AI agents use it:**
They read this file before writing any code, ensuring everything they create follows your project's standards perfectly.
Your project context is saved and ready to help agents implement consistently!"
### 5. Final File Updates
Update the project context file with completion information:
**Frontmatter Update:**
```yaml
---
project_name: '{{project_name}}'
user_name: '{{user_name}}'
date: '{{date}}'
sections_completed:
['technology_stack', 'engine_rules', 'performance_rules', 'organization_rules', 'testing_rules', 'platform_rules', 'anti_patterns']
status: 'complete'
rule_count: { { total_rules } }
optimized_for_llm: true
---
```
**Add Usage Section:**
Append the usage guidelines from step 3 to complete the document.
### 6. Completion Validation
Final checks before completion:
**Content Validation:**
- All critical technology versions documented
- Engine-specific rules are specific and actionable
- Performance rules capture project requirements
- Code organization rules maintain standards
- Testing rules ensure consistency
- Platform rules prevent cross-platform issues
- Anti-pattern rules prevent common mistakes
**Format Validation:**
- Content is lean and optimized for LLMs
- Structure is logical and scannable
- No redundant or obvious information
- Consistent formatting throughout
### 7. Completion Message
Present final completion to user:
"**Project Context Generation Complete!**
Your optimized project context file is ready at:
`{output_folder}/project-context.md`
**Context Summary:**
- {{rule_count}} critical rules for AI agents
- {{section_count}} comprehensive sections
- Optimized for LLM context efficiency
- Ready for immediate agent integration
**Key Benefits:**
- Consistent implementation across all AI agents
- Reduced common mistakes and edge cases
- Clear guidance for project-specific patterns
- Minimal LLM context usage
**Next Steps:**
1. AI agents will automatically read this file when implementing
2. Update this file when your technology stack or patterns evolve
3. Review quarterly to optimize and remove outdated rules
Your project context will help ensure high-quality, consistent game implementation across all development work. Great work capturing your project's critical implementation requirements!"
## SUCCESS METRICS:
- Complete project context file with all critical rules
- Content optimized for LLM context efficiency
- All technology versions and patterns documented
- File structure is logical and scannable
- Usage guidelines included for agents and humans
- Frontmatter properly updated with completion status
- User provided with clear next steps and benefits
## FAILURE MODES:
- Final content is too verbose for LLM consumption
- Missing critical implementation rules or patterns
- Not optimizing content for agent readability
- Not providing clear usage guidelines
- Frontmatter not properly updated
- Not validating file completion before ending
## WORKFLOW COMPLETE:
This is the final step of the Generate Project Context workflow. The user now has a comprehensive, optimized project context file that will ensure consistent, high-quality game implementation across all AI agents working on the project.
The project context file serves as the critical "rules of the road" that agents need to implement game code consistently with the project's standards and patterns.

View File

@ -0,0 +1,48 @@
---
name: generate-project-context
description: Creates a concise project-context.md file with critical rules and patterns that AI agents must follow when implementing game code. Optimized for LLM context efficiency.
---
# Generate Project Context Workflow
**Goal:** Create a concise, optimized `project-context.md` file containing critical rules, patterns, and guidelines that AI agents must follow when implementing game code. This file focuses on unobvious details that LLMs need to be reminded of.
**Your Role:** You are a technical facilitator working with a peer to capture the essential implementation rules that will ensure consistent, high-quality game code generation across all AI agents working on the project.
---
## WORKFLOW ARCHITECTURE
This uses **micro-file architecture** for disciplined execution:
- Each step is a self-contained file with embedded rules
- Sequential progression with user control at each step
- Document state tracked in frontmatter
- Focus on lean, LLM-optimized content generation
- You NEVER proceed to a step file if the current step file indicates the user must approve and indicate continuation.
---
## INITIALIZATION
### Configuration Loading
Load config from `{project-root}/_bmad/bmgd/config.yaml` and resolve:
- `project_name`, `output_folder`, `user_name`
- `communication_language`, `document_output_language`, `game_dev_experience`
- `date` as system-generated current datetime
### Paths
- `installed_path` = `{project-root}/_bmad/bmgd/workflows/3-technical/generate-project-context`
- `template_path` = `{installed_path}/project-context-template.md`
- `output_file` = `{output_folder}/project-context.md`
---
## EXECUTION
Load and execute `steps/step-01-discover.md` to begin the workflow.
**Note:** Input document discovery and initialization protocols are handled in step-01-discover.md.

View File

@ -13,12 +13,13 @@ const { XmlHandler } = require('../../../lib/xml-handler');
const { DependencyResolver } = require('./dependency-resolver');
const { ConfigCollector } = require('./config-collector');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
const { AgentPartyGenerator } = require('../../../lib/agent-party-generator');
const { CLIUtils } = require('../../../lib/cli-utils');
const { ManifestGenerator } = require('./manifest-generator');
const { IdeConfigManager } = require('./ide-config-manager');
const { CustomHandler } = require('../custom/handler');
const { filterCustomizationData } = require('../../../lib/agent/compiler');
// BMAD installation folder name - this is constant and should never change
const BMAD_FOLDER_NAME = '_bmad';
class Installer {
constructor() {
@ -34,58 +35,35 @@ class Installer {
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;
}
/**
* Find the bmad installation directory in a project
* V6+ installations can use ANY folder name but ALWAYS have _config/manifest.yaml
* Always uses the standard _bmad folder name
* Also checks for legacy _cfg folder for migration
* @param {string} projectDir - Project directory
* @returns {Promise<Object>} { bmadDir: string, hasLegacyCfg: boolean }
*/
async findBmadDir(projectDir) {
const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME);
// Check if project directory exists
if (!(await fs.pathExists(projectDir))) {
// Project doesn't exist yet, return default
return { bmadDir: path.join(projectDir, '_bmad'), hasLegacyCfg: false };
return { bmadDir, hasLegacyCfg: false };
}
let bmadDir = null;
// Check for legacy _cfg folder if bmad directory exists
let hasLegacyCfg = false;
try {
const entries = await fs.readdir(projectDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory()) {
const bmadPath = path.join(projectDir, entry.name);
// Check for current _config folder
const manifestPath = path.join(bmadPath, '_config', 'manifest.yaml');
if (await fs.pathExists(manifestPath)) {
// Found a V6+ installation with current _config folder
return { bmadDir: bmadPath, hasLegacyCfg: false };
}
// Check for legacy _cfg folder
const legacyManifestPath = path.join(bmadPath, '_cfg', 'manifest.yaml');
if (await fs.pathExists(legacyManifestPath)) {
bmadDir = bmadPath;
hasLegacyCfg = true;
}
}
if (await fs.pathExists(bmadDir)) {
const legacyCfgPath = path.join(bmadDir, '_cfg');
if (await fs.pathExists(legacyCfgPath)) {
hasLegacyCfg = true;
}
} catch {
console.log(chalk.red('Error reading project directory for BMAD installation detection'));
}
// If we found a bmad directory (with or without legacy _cfg)
if (bmadDir) {
return { bmadDir, hasLegacyCfg };
}
// No V6+ installation found, return default
// This will be used for new installations
return { bmadDir: path.join(projectDir, '_bmad'), hasLegacyCfg: false };
return { bmadDir, hasLegacyCfg };
}
/**
@ -120,7 +98,7 @@ class Installer {
*
* 3. Document marker in instructions.md (if applicable)
*/
async copyFileWithPlaceholderReplacement(sourcePath, targetPath, bmadFolderName) {
async copyFileWithPlaceholderReplacement(sourcePath, targetPath) {
// List of text file extensions that should have placeholder replacement
const textExtensions = ['.md', '.yaml', '.yml', '.txt', '.json', '.js', '.ts', '.html', '.css', '.sh', '.bat', '.csv', '.xml'];
const ext = path.extname(sourcePath).toLowerCase();
@ -285,7 +263,7 @@ class Installer {
// Check for already configured IDEs
const { Detector } = require('./detector');
const detector = new Detector();
const bmadDir = path.join(projectDir, this.bmadFolderName || 'bmad');
const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME);
// During full reinstall, use the saved previous IDEs since bmad dir was deleted
// Otherwise detect from existing installation
@ -532,18 +510,14 @@ class Installer {
}
}
// Always use _bmad as the folder name
const bmadFolderName = '_bmad';
this.bmadFolderName = bmadFolderName; // Store for use in other methods
// Store AgentVibes configuration for injection point processing
this.enableAgentVibes = config.enableAgentVibes || false;
// Set bmad folder name on module manager and IDE manager for placeholder replacement
this.moduleManager.setBmadFolderName(bmadFolderName);
this.moduleManager.setBmadFolderName(BMAD_FOLDER_NAME);
this.moduleManager.setCoreConfig(moduleConfigs.core || {});
this.moduleManager.setCustomModulePaths(customModulePaths);
this.ideManager.setBmadFolderName(bmadFolderName);
this.ideManager.setBmadFolderName(BMAD_FOLDER_NAME);
// Tool selection will be collected after we determine if it's a reinstall/update/new install
@ -553,14 +527,8 @@ class Installer {
// Resolve target directory (path.resolve handles platform differences)
const projectDir = path.resolve(config.directory);
let existingBmadDir = null;
let existingBmadFolderName = null;
if (await fs.pathExists(projectDir)) {
const result = await this.findBmadDir(projectDir);
existingBmadDir = result.bmadDir;
existingBmadFolderName = path.basename(existingBmadDir);
}
// Always use the standard _bmad folder name
const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME);
// Create a project directory if it doesn't exist (user already confirmed)
if (!(await fs.pathExists(projectDir))) {
@ -582,8 +550,6 @@ class Installer {
}
}
const bmadDir = path.join(projectDir, bmadFolderName);
// Check existing installation
spinner.text = 'Checking for existing installation...';
const existingInstall = await this.detector.detect(bmadDir);
@ -1606,7 +1572,7 @@ class Installer {
const targetPath = path.join(agentsDir, fileName);
if (await fs.pathExists(sourcePath)) {
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
this.installedFiles.add(targetPath);
}
}
@ -1622,7 +1588,7 @@ class Installer {
const targetPath = path.join(tasksDir, fileName);
if (await fs.pathExists(sourcePath)) {
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
this.installedFiles.add(targetPath);
}
}
@ -1638,7 +1604,7 @@ class Installer {
const targetPath = path.join(toolsDir, fileName);
if (await fs.pathExists(sourcePath)) {
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
this.installedFiles.add(targetPath);
}
}
@ -1654,7 +1620,7 @@ class Installer {
const targetPath = path.join(templatesDir, fileName);
if (await fs.pathExists(sourcePath)) {
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
this.installedFiles.add(targetPath);
}
}
@ -1669,7 +1635,7 @@ class Installer {
await fs.ensureDir(path.dirname(targetPath));
if (await fs.pathExists(dataPath)) {
await this.copyFileWithPlaceholderReplacement(dataPath, targetPath, this.bmadFolderName || 'bmad');
await this.copyFileWithPlaceholderReplacement(dataPath, targetPath);
this.installedFiles.add(targetPath);
}
}
@ -1759,14 +1725,9 @@ class Installer {
}
}
// Check if this is a workflow.yaml file
if (file.endsWith('workflow.yaml')) {
await fs.ensureDir(path.dirname(targetFile));
await this.copyWorkflowYamlStripped(sourceFile, targetFile);
} else {
// Copy the file with placeholder replacement
await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile, this.bmadFolderName || 'bmad');
}
// Copy the file with placeholder replacement
await fs.ensureDir(path.dirname(targetFile));
await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile);
// Track the installed file
this.installedFiles.add(targetFile);
@ -1844,7 +1805,7 @@ class Installer {
if (!(await fs.pathExists(customizePath))) {
const genericTemplatePath = getSourcePath('utility', 'agent-components', 'agent.customize.template.yaml');
if (await fs.pathExists(genericTemplatePath)) {
await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath, this.bmadFolderName || 'bmad');
await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath);
if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`));
}
@ -1853,235 +1814,6 @@ class Installer {
}
}
/**
* Build standalone agents in bmad/agents/ directory
* @param {string} bmadDir - Path to bmad directory
* @param {string} projectDir - Path to project directory
*/
async buildStandaloneAgents(bmadDir, projectDir) {
const standaloneAgentsPath = path.join(bmadDir, 'agents');
const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
// Check if standalone agents directory exists
if (!(await fs.pathExists(standaloneAgentsPath))) {
return;
}
// Get all subdirectories in agents/
const agentDirs = await fs.readdir(standaloneAgentsPath, { withFileTypes: true });
for (const agentDir of agentDirs) {
if (!agentDir.isDirectory()) continue;
const agentDirPath = path.join(standaloneAgentsPath, agentDir.name);
// Find any .agent.yaml file in the directory
const files = await fs.readdir(agentDirPath);
const yamlFile = files.find((f) => f.endsWith('.agent.yaml'));
if (!yamlFile) continue;
const agentName = path.basename(yamlFile, '.agent.yaml');
const sourceYamlPath = path.join(agentDirPath, yamlFile);
const targetMdPath = path.join(agentDirPath, `${agentName}.md`);
const customizePath = path.join(cfgAgentsDir, `${agentName}.customize.yaml`);
// Check for customizations
const customizeExists = await fs.pathExists(customizePath);
let customizedFields = [];
if (customizeExists) {
const customizeContent = await fs.readFile(customizePath, 'utf8');
const yaml = require('yaml');
const customizeYaml = yaml.parse(customizeContent);
// Detect what fields are customized (similar to rebuildAgentFiles)
if (customizeYaml) {
if (customizeYaml.persona) {
for (const [key, value] of Object.entries(customizeYaml.persona)) {
if (value !== '' && value !== null && !(Array.isArray(value) && value.length === 0)) {
customizedFields.push(`persona.${key}`);
}
}
}
if (customizeYaml.agent?.metadata) {
for (const [key, value] of Object.entries(customizeYaml.agent.metadata)) {
if (value !== '' && value !== null) {
customizedFields.push(`metadata.${key}`);
}
}
}
if (customizeYaml.critical_actions && customizeYaml.critical_actions.length > 0) {
customizedFields.push('critical_actions');
}
if (customizeYaml.menu && customizeYaml.menu.length > 0) {
customizedFields.push('menu');
}
}
}
// Build YAML to XML .md
let xmlContent = await this.xmlHandler.buildFromYaml(sourceYamlPath, customizeExists ? customizePath : null, {
includeMetadata: true,
});
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
// Process TTS injection points (pass targetPath for tracking)
xmlContent = this.processTTSInjectionPoints(xmlContent, targetMdPath);
// Write the built .md file with POSIX-compliant final newline
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
await fs.writeFile(targetMdPath, content, 'utf8');
// Display result
if (customizedFields.length > 0) {
console.log(chalk.dim(` Built standalone agent: ${agentName}.md `) + chalk.yellow(`(customized: ${customizedFields.join(', ')})`));
} else {
console.log(chalk.dim(` Built standalone agent: ${agentName}.md`));
}
}
}
/**
* Rebuild agent files from installer source (for compile command)
* @param {string} modulePath - Path to module in bmad/ installation
* @param {string} moduleName - Module name
*/
async rebuildAgentFiles(modulePath, moduleName) {
// Get source agents directory from installer
const sourceAgentsPath =
moduleName === 'core' ? path.join(getModulePath('core'), 'agents') : path.join(getSourcePath(`modules/${moduleName}`), 'agents');
if (!(await fs.pathExists(sourceAgentsPath))) {
return; // No source agents to rebuild
}
// Determine project directory (parent of bmad/ directory)
const bmadDir = path.dirname(modulePath);
const projectDir = path.dirname(bmadDir);
const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
const targetAgentsPath = path.join(modulePath, 'agents');
// Ensure target directory exists
await fs.ensureDir(targetAgentsPath);
// Get all YAML agent files from source
const sourceFiles = await fs.readdir(sourceAgentsPath);
for (const file of sourceFiles) {
if (file.endsWith('.agent.yaml')) {
const agentName = file.replace('.agent.yaml', '');
const sourceYamlPath = path.join(sourceAgentsPath, file);
const targetMdPath = path.join(targetAgentsPath, `${agentName}.md`);
const customizePath = path.join(cfgAgentsDir, `${moduleName}-${agentName}.customize.yaml`);
// Check for customizations
const customizeExists = await fs.pathExists(customizePath);
let customizedFields = [];
if (customizeExists) {
const customizeContent = await fs.readFile(customizePath, 'utf8');
const yaml = require('yaml');
const customizeYaml = yaml.parse(customizeContent);
// Detect what fields are customized
if (customizeYaml) {
if (customizeYaml.persona) {
for (const [key, value] of Object.entries(customizeYaml.persona)) {
if (value !== '' && value !== null && !(Array.isArray(value) && value.length === 0)) {
customizedFields.push(`persona.${key}`);
}
}
}
if (customizeYaml.agent?.metadata) {
for (const [key, value] of Object.entries(customizeYaml.agent.metadata)) {
if (value !== '' && value !== null) {
customizedFields.push(`metadata.${key}`);
}
}
}
if (customizeYaml.critical_actions && customizeYaml.critical_actions.length > 0) {
customizedFields.push('critical_actions');
}
if (customizeYaml.memories && customizeYaml.memories.length > 0) {
customizedFields.push('memories');
}
if (customizeYaml.menu && customizeYaml.menu.length > 0) {
customizedFields.push('menu');
}
if (customizeYaml.prompts && customizeYaml.prompts.length > 0) {
customizedFields.push('prompts');
}
}
}
// Read the YAML content
const yamlContent = await fs.readFile(sourceYamlPath, 'utf8');
// Read customize content if exists
let customizeData = {};
if (customizeExists) {
const customizeContent = await fs.readFile(customizePath, 'utf8');
const yaml = require('yaml');
customizeData = yaml.parse(customizeContent);
}
// Build agent answers from customize data (filter empty values)
const answers = {};
if (customizeData.persona) {
Object.assign(answers, filterCustomizationData(customizeData.persona));
}
if (customizeData.agent?.metadata) {
const filteredMetadata = filterCustomizationData(customizeData.agent.metadata);
if (Object.keys(filteredMetadata).length > 0) {
Object.assign(answers, { metadata: filteredMetadata });
}
}
if (customizeData.critical_actions && customizeData.critical_actions.length > 0) {
answers.critical_actions = customizeData.critical_actions;
}
if (customizeData.memories && customizeData.memories.length > 0) {
answers.memories = customizeData.memories;
}
const coreConfigPath = path.join(bmadDir, 'core', 'config.yaml');
let coreConfig = {};
if (await fs.pathExists(coreConfigPath)) {
const yaml = require('yaml');
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
coreConfig = yaml.parse(coreConfigContent);
}
// Compile using the same compiler as initial installation
const { compileAgent } = require('../../../lib/agent/compiler');
const result = await compileAgent(yamlContent, answers, agentName, path.relative(bmadDir, targetMdPath), {
config: coreConfig,
});
// Check if compilation succeeded
if (!result || !result.xml) {
throw new Error(`Failed to compile agent ${agentName}: No XML returned from compiler`);
}
// Replace _bmad with actual folder name if needed
const finalXml = result.xml.replaceAll('_bmad', path.basename(bmadDir));
// Write the rebuilt .md file with POSIX-compliant final newline
const content = finalXml.endsWith('\n') ? finalXml : finalXml + '\n';
await fs.writeFile(targetMdPath, content, 'utf8');
// Display result with customizations if any
if (customizedFields.length > 0) {
console.log(chalk.dim(` Rebuilt agent: ${agentName}.md `) + chalk.yellow(`(customized: ${customizedFields.join(', ')})`));
} else {
console.log(chalk.dim(` Rebuilt agent: ${agentName}.md`));
}
}
}
}
/**
* Private: Update core
*/
@ -2677,190 +2409,6 @@ class Installer {
return { customFiles, modifiedFiles };
}
/**
* Private: Create agent configuration files
* @param {string} bmadDir - BMAD installation directory
* @param {Object} userInfo - User information including name and language
*/
async createAgentConfigs(bmadDir, userInfo = null) {
const agentConfigDir = path.join(bmadDir, '_config', 'agents');
await fs.ensureDir(agentConfigDir);
// Get all agents from all modules
const agents = [];
const agentDetails = []; // For manifest generation
// Check modules for agents (including core)
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory() && entry.name !== '_config') {
const moduleAgentsPath = path.join(bmadDir, entry.name, 'agents');
if (await fs.pathExists(moduleAgentsPath)) {
const agentFiles = await fs.readdir(moduleAgentsPath);
for (const agentFile of agentFiles) {
if (agentFile.endsWith('.md')) {
const agentPath = path.join(moduleAgentsPath, agentFile);
const agentContent = await fs.readFile(agentPath, 'utf8');
// Skip agents with localskip="true"
const hasLocalSkip = agentContent.match(/<agent[^>]*\slocalskip="true"[^>]*>/);
if (hasLocalSkip) {
continue; // Skip this agent - it should not have been installed
}
const agentName = path.basename(agentFile, '.md');
// Extract any nodes with agentConfig="true"
const agentConfigNodes = this.extractAgentConfigNodes(agentContent);
agents.push({
name: agentName,
module: entry.name,
agentConfigNodes: agentConfigNodes,
});
// Use shared AgentPartyGenerator to extract details
let details = AgentPartyGenerator.extractAgentDetails(agentContent, entry.name, agentName);
// Apply config overrides if they exist
if (details) {
const configPath = path.join(agentConfigDir, `${entry.name}-${agentName}.md`);
if (await fs.pathExists(configPath)) {
const configContent = await fs.readFile(configPath, 'utf8');
details = AgentPartyGenerator.applyConfigOverrides(details, configContent);
}
agentDetails.push(details);
}
}
}
}
}
}
// Create config file for each agent
let createdCount = 0;
let skippedCount = 0;
// Load agent config template
const templatePath = getSourcePath('utility', 'models', 'agent-config-template.md');
const templateContent = await fs.readFile(templatePath, 'utf8');
for (const agent of agents) {
const configPath = path.join(agentConfigDir, `${agent.module}-${agent.name}.md`);
// Skip if config file already exists (preserve custom configurations)
if (await fs.pathExists(configPath)) {
skippedCount++;
continue;
}
// Build config content header
let configContent = `# Agent Config: ${agent.name}\n\n`;
// Process template and add agent-specific config nodes
let processedTemplate = templateContent;
// Replace {core:user_name} placeholder with actual user name if available
if (userInfo && userInfo.userName) {
processedTemplate = processedTemplate.replaceAll('{core:user_name}', userInfo.userName);
}
// Replace {core:communication_language} placeholder with actual language if available
if (userInfo && userInfo.responseLanguage) {
processedTemplate = processedTemplate.replaceAll('{core:communication_language}', userInfo.responseLanguage);
}
// If this agent has agentConfig nodes, add them after the existing comment
if (agent.agentConfigNodes && agent.agentConfigNodes.length > 0) {
// Find the agent-specific configuration nodes comment
const commentPattern = /(\s*<!-- Agent-specific configuration nodes -->)/;
const commentMatch = processedTemplate.match(commentPattern);
if (commentMatch) {
// Add nodes right after the comment
let agentSpecificNodes = '';
for (const node of agent.agentConfigNodes) {
agentSpecificNodes += `\n ${node}`;
}
processedTemplate = processedTemplate.replace(commentPattern, `$1${agentSpecificNodes}`);
}
}
configContent += processedTemplate;
// Ensure POSIX-compliant final newline
if (!configContent.endsWith('\n')) {
configContent += '\n';
}
await fs.writeFile(configPath, configContent, 'utf8');
this.installedFiles.add(configPath); // Track agent config files
createdCount++;
}
// Generate agent manifest with overrides applied
await this.generateAgentManifest(bmadDir, agentDetails);
return { total: agents.length, created: createdCount, skipped: skippedCount };
}
/**
* Generate agent manifest XML file
* @param {string} bmadDir - BMAD installation directory
* @param {Array} agentDetails - Array of agent details
*/
async generateAgentManifest(bmadDir, agentDetails) {
const manifestPath = path.join(bmadDir, '_config', 'agent-manifest.csv');
await AgentPartyGenerator.writeAgentParty(manifestPath, agentDetails, { forWeb: false });
}
/**
* Extract nodes with agentConfig="true" from agent content
* @param {string} content - Agent file content
* @returns {Array} Array of XML nodes that should be added to agent config
*/
extractAgentConfigNodes(content) {
const nodes = [];
try {
// Find all XML nodes with agentConfig="true"
// Match self-closing tags and tags with content
const selfClosingPattern = /<([a-zA-Z][a-zA-Z0-9_-]*)\s+[^>]*agentConfig="true"[^>]*\/>/g;
const withContentPattern = /<([a-zA-Z][a-zA-Z0-9_-]*)\s+[^>]*agentConfig="true"[^>]*>([\s\S]*?)<\/\1>/g;
// Extract self-closing tags
let match;
while ((match = selfClosingPattern.exec(content)) !== null) {
// Extract just the tag without children (structure only)
const tagMatch = match[0].match(/<([a-zA-Z][a-zA-Z0-9_-]*)([^>]*)\/>/);
if (tagMatch) {
const tagName = tagMatch[1];
const attributes = tagMatch[2].replace(/\s*agentConfig="true"/, ''); // Remove agentConfig attribute
nodes.push(`<${tagName}${attributes}></${tagName}>`);
}
}
// Extract tags with content
while ((match = withContentPattern.exec(content)) !== null) {
const fullMatch = match[0];
const tagName = match[1];
// Extract opening tag with attributes (removing agentConfig="true")
const openingTagMatch = fullMatch.match(new RegExp(`<${tagName}([^>]*)>`));
if (openingTagMatch) {
const attributes = openingTagMatch[1].replace(/\s*agentConfig="true"/, '');
// Add empty node structure (no children)
nodes.push(`<${tagName}${attributes}></${tagName}>`);
}
}
} catch (error) {
console.error('Error extracting agentConfig nodes:', error);
}
return nodes;
}
/**
* Handle missing custom module sources interactively
* @param {Map} customModuleSources - Map of custom module ID to info
@ -2999,7 +2547,7 @@ class Installer {
await this.manifest.addCustomModule(bmadDir, missing.info);
validCustomModules.push({
id: moduleId,
id: missing.id,
name: missing.name,
path: resolvedPath,
info: missing.info,
@ -3013,7 +2561,7 @@ class Installer {
case 'remove': {
// Extra confirmation for destructive remove
console.log(chalk.red.bold(`\n⚠️ WARNING: This will PERMANENTLY DELETE "${missing.name}" and all its files!`));
console.log(chalk.red(` Module location: ${path.join(bmadDir, moduleId)}`));
console.log(chalk.red(` Module location: ${path.join(bmadDir, missing.id)}`));
const { confirm } = await inquirer.prompt([
{

File diff suppressed because it is too large Load Diff

View File

@ -731,7 +731,7 @@ class ModuleManager {
async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir, installer = null) {
const sourceAgentsPath = path.join(sourcePath, 'agents');
const targetAgentsPath = path.join(targetPath, 'agents');
const cfgAgentsDir = path.join(bmadDir, '_bmad', '_config', 'agents');
const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
// Check if agents directory exists in source
if (!(await fs.pathExists(sourceAgentsPath))) {