Compare commits
14 Commits
7d705aa08b
...
72a8f3248b
| Author | SHA1 | Date |
|---|---|---|
|
|
72a8f3248b | |
|
|
251ec93150 | |
|
|
3a663a9a92 | |
|
|
133181aaa9 | |
|
|
32b104b4bc | |
|
|
e9c0aafad9 | |
|
|
b88845c0fe | |
|
|
1dca5fb4b7 | |
|
|
57bd2c0731 | |
|
|
e39aa33eea | |
|
|
2da9aebaa8 | |
|
|
5c756b6404 | |
|
|
52bd250a8c | |
|
|
b6ade22984 |
|
|
@ -29,6 +29,7 @@ Thumbs.db
|
|||
.prettierrc
|
||||
|
||||
# IDE and editor configs
|
||||
.idea/
|
||||
.windsurf/
|
||||
.trae/
|
||||
_bmad*/.cursor/
|
||||
|
|
@ -66,6 +67,7 @@ shared-modules
|
|||
z*/
|
||||
|
||||
_bmad
|
||||
_bmad-output/
|
||||
.claude
|
||||
.codex
|
||||
.github/chatmodes
|
||||
|
|
|
|||
20
CHANGELOG.md
20
CHANGELOG.md
|
|
@ -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**
|
||||
|
|
|
|||
63
README.md
63
README.md
|
|
@ -79,6 +79,8 @@ With **BMad Builder**, you can architect both simple agents and vastly complex d
|
|||
|
||||
### 1. Install BMad Method
|
||||
|
||||
#### Interactive Installation (Default)
|
||||
|
||||
```bash
|
||||
# Install v6 Alpha (recommended)
|
||||
npx bmad-method@alpha install
|
||||
|
|
@ -87,6 +89,65 @@ npx bmad-method@alpha install
|
|||
npx bmad-method install
|
||||
```
|
||||
|
||||
#### Non-Interactive Installation (CI/CD, Automation)
|
||||
|
||||
For automated deployments and CI/CD pipelines:
|
||||
|
||||
```bash
|
||||
# Minimal installation with defaults
|
||||
npx bmad-method@alpha install -y
|
||||
|
||||
# Custom configuration
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=Alice \
|
||||
--skill-level=advanced \
|
||||
--output-folder=.bmad-output
|
||||
|
||||
# Team-based installation (fullstack team)
|
||||
npx bmad-method@alpha install -y --team=fullstack
|
||||
|
||||
# Team with modifications
|
||||
npx bmad-method@alpha install -y --team=fullstack --agents=+dev
|
||||
|
||||
# Selective agents and workflows
|
||||
npx bmad-method@alpha install -y \
|
||||
--agents=dev,architect,pm \
|
||||
--workflows=create-prd,create-tech-spec,dev-story
|
||||
|
||||
# Profile-based installation
|
||||
npx bmad-method@alpha install -y --profile=minimal
|
||||
npx bmad-method@alpha install -y --profile=solo-dev
|
||||
```
|
||||
|
||||
**Available Options:**
|
||||
|
||||
- `-y, --non-interactive` - Skip all prompts, use defaults
|
||||
- `--user-name <name>` - User name for configuration
|
||||
- `--skill-level <level>` - beginner, intermediate, advanced
|
||||
- `--output-folder <path>` - Output folder for BMAD artifacts
|
||||
- `--modules <list>` - Comma-separated module list
|
||||
- `--agents <list>` - Comma-separated agent list or 'all', 'none'
|
||||
- `--workflows <list>` - Comma-separated workflow list or 'all', 'none'
|
||||
- `--team <name>` - Install predefined team (fullstack, gamedev)
|
||||
- `--profile <name>` - Installation profile (minimal, full, solo-dev, team)
|
||||
|
||||
**Modifiers:**
|
||||
|
||||
- `--agents=+dev` - Add agent to team/profile selection
|
||||
- `--agents=-dev` - Remove agent from team/profile selection
|
||||
|
||||
**Available Teams:**
|
||||
|
||||
- `fullstack` - analyst, architect, pm, sm, ux-designer
|
||||
- `gamedev` - game-designer, game-dev, game-architect, game-scrum-master
|
||||
|
||||
**Available Profiles:**
|
||||
|
||||
- `minimal` - Core + dev agent + essential workflows
|
||||
- `full` - Everything (all modules, agents, workflows)
|
||||
- `solo-dev` - Single developer setup
|
||||
- `team` - Team collaboration setup
|
||||
|
||||
### 2. Initialize Your Project
|
||||
|
||||
Load any agent in your IDE and run:
|
||||
|
|
@ -231,6 +292,8 @@ MIT License - See [LICENSE](LICENSE) for details.
|
|||
|
||||
**Trademarks:** BMad™ and BMAD-METHOD™ are trademarks of BMad Code, LLC.
|
||||
|
||||
Supported by: <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">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,448 @@
|
|||
# Non-Interactive Installation Guide
|
||||
|
||||
This guide helps you convert interactive BMAD installations to non-interactive CLI commands for automation, CI/CD pipelines, and scripted deployments.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Quick Start](#quick-start)
|
||||
- [Migration from Interactive to CLI](#migration-from-interactive-to-cli)
|
||||
- [Common Use Cases](#common-use-cases)
|
||||
- [CLI Options Reference](#cli-options-reference)
|
||||
- [Team-Based Installation](#team-based-installation)
|
||||
- [Profile-Based Installation](#profile-based-installation)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Minimal Non-Interactive Installation
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y
|
||||
```
|
||||
|
||||
This installs BMAD with:
|
||||
|
||||
- Default user name from system (USER environment variable)
|
||||
- Intermediate skill level
|
||||
- Default output folder (`_bmad-output`)
|
||||
- BMM module
|
||||
- All agents and workflows from BMM
|
||||
|
||||
### Custom Non-Interactive Installation
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=YourName \
|
||||
--skill-level=advanced \
|
||||
--output-folder=.artifacts
|
||||
```
|
||||
|
||||
## Migration from Interactive to CLI
|
||||
|
||||
### Step 1: Note Your Current Configuration
|
||||
|
||||
If you have an existing BMAD installation, check your configuration:
|
||||
|
||||
```bash
|
||||
# View your current configuration
|
||||
cat _bmad/core/config.yaml
|
||||
cat _bmad/bmm/config.yaml
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```yaml
|
||||
user_name: Alice
|
||||
user_skill_level: intermediate
|
||||
output_folder: '{project-root}/_bmad-output'
|
||||
communication_language: English
|
||||
```
|
||||
|
||||
### Step 2: Convert to CLI Command
|
||||
|
||||
Based on your configuration, build the equivalent CLI command:
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=Alice \
|
||||
--skill-level=intermediate \
|
||||
--output-folder=_bmad-output \
|
||||
--communication-language=English
|
||||
```
|
||||
|
||||
### Step 3: Replicate Module and Agent Selection
|
||||
|
||||
Check what agents and workflows you currently have:
|
||||
|
||||
```bash
|
||||
# View installed agents
|
||||
cat _bmad/_config/agents.csv
|
||||
|
||||
# View installed workflows
|
||||
cat _bmad/_config/workflows.csv
|
||||
```
|
||||
|
||||
If you have specific agents installed, add them to your command:
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=Alice \
|
||||
--agents=dev,architect,pm
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### 1. CI/CD Pipeline Installation
|
||||
|
||||
```yaml
|
||||
# .github/workflows/setup-bmad.yml
|
||||
name: Setup BMAD
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '20'
|
||||
- name: Install BMAD
|
||||
run: npx bmad-method@alpha install -y --profile=minimal
|
||||
```
|
||||
|
||||
### 2. Docker Container Setup
|
||||
|
||||
```dockerfile
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# Install BMAD non-interactively
|
||||
RUN npx bmad-method@alpha install -y \
|
||||
--user-name=ContainerUser \
|
||||
--skill-level=intermediate \
|
||||
--output-folder=.bmad-output
|
||||
|
||||
CMD ["npm", "start"]
|
||||
```
|
||||
|
||||
### 3. Team Onboarding Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# onboard-developer.sh
|
||||
|
||||
echo "Setting up BMAD for $USER..."
|
||||
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=$USER \
|
||||
--skill-level=intermediate \
|
||||
--team=fullstack \
|
||||
--output-folder=.bmad-output
|
||||
|
||||
echo "BMAD installation complete!"
|
||||
```
|
||||
|
||||
### 4. Infrastructure as Code
|
||||
|
||||
```bash
|
||||
# terraform/setup.sh
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=TerraformBot \
|
||||
--skill-level=advanced \
|
||||
--modules=core,bmm \
|
||||
--agents=dev,architect,analyst \
|
||||
--workflows=create-prd,create-architecture,dev-story
|
||||
```
|
||||
|
||||
### 5. Minimal Developer Setup
|
||||
|
||||
For developers who only need code generation:
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y \
|
||||
--profile=minimal \
|
||||
--user-name=$USER
|
||||
```
|
||||
|
||||
## CLI Options Reference
|
||||
|
||||
### Core Options
|
||||
|
||||
| Option | Description | Default | Example |
|
||||
| --------------------------------- | ---------------------- | -------------- | ---------------------------------- |
|
||||
| `-y, --non-interactive` | Skip all prompts | `false` | `install -y` |
|
||||
| `--user-name <name>` | User name | System user | `--user-name=Alice` |
|
||||
| `--skill-level <level>` | Skill level | `intermediate` | `--skill-level=advanced` |
|
||||
| `--output-folder <path>` | Output folder | `_bmad-output` | `--output-folder=.artifacts` |
|
||||
| `--communication-language <lang>` | Communication language | `English` | `--communication-language=Spanish` |
|
||||
| `--document-language <lang>` | Document language | `English` | `--document-language=French` |
|
||||
|
||||
### Module & Selection Options
|
||||
|
||||
| Option | Description | Example |
|
||||
| -------------------- | ------------------------- | ---------------------------------- |
|
||||
| `--modules <list>` | Comma-separated modules | `--modules=core,bmm,bmbb` |
|
||||
| `--agents <list>` | Comma-separated agents | `--agents=dev,architect,pm` |
|
||||
| `--workflows <list>` | Comma-separated workflows | `--workflows=create-prd,dev-story` |
|
||||
|
||||
### Team & Profile Options
|
||||
|
||||
| Option | Description | Example |
|
||||
| ------------------ | ----------------------- | ------------------- |
|
||||
| `--team <name>` | Install predefined team | `--team=fullstack` |
|
||||
| `--profile <name>` | Installation profile | `--profile=minimal` |
|
||||
|
||||
## Team-Based Installation
|
||||
|
||||
Teams are predefined bundles of agents and workflows optimized for specific use cases.
|
||||
|
||||
### Available Teams
|
||||
|
||||
#### Fullstack Team
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y --team=fullstack
|
||||
```
|
||||
|
||||
**Includes:**
|
||||
|
||||
- Agents: analyst, architect, pm, sm, ux-designer
|
||||
- Module: BMM
|
||||
|
||||
**Use for:** Full product development teams
|
||||
|
||||
#### Game Development Team
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y --team=gamedev
|
||||
```
|
||||
|
||||
**Includes:**
|
||||
|
||||
- Agents: game-designer, game-dev, game-architect, game-scrum-master
|
||||
- Workflows: brainstorm-game, game-brief, gdd, narrative
|
||||
- Module: BMGD (Game Development)
|
||||
|
||||
**Use for:** Game development projects
|
||||
|
||||
### Modifying Team Selections
|
||||
|
||||
You can add or remove agents from a team:
|
||||
|
||||
```bash
|
||||
# Add dev agent to fullstack team
|
||||
npx bmad-method@alpha install -y --team=fullstack --agents=+dev
|
||||
|
||||
# Remove ux-designer from fullstack team
|
||||
npx bmad-method@alpha install -y --team=fullstack --agents=-ux-designer
|
||||
|
||||
# Add and remove multiple
|
||||
npx bmad-method@alpha install -y --team=fullstack --agents=+dev,+tea,-ux-designer
|
||||
```
|
||||
|
||||
## Profile-Based Installation
|
||||
|
||||
Profiles are pre-configured installations for common scenarios.
|
||||
|
||||
### Available Profiles
|
||||
|
||||
#### Minimal Profile
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y --profile=minimal
|
||||
```
|
||||
|
||||
**Includes:**
|
||||
|
||||
- Modules: core
|
||||
- Agents: dev
|
||||
- Workflows: create-tech-spec, quick-dev
|
||||
|
||||
**Use for:** Simple development, code generation only
|
||||
|
||||
#### Solo Developer Profile
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y --profile=solo-dev
|
||||
```
|
||||
|
||||
**Includes:**
|
||||
|
||||
- Modules: core, bmm
|
||||
- Agents: dev, architect, analyst, tech-writer
|
||||
- Workflows: create-tech-spec, quick-dev, dev-story, code-review, create-prd, create-architecture
|
||||
|
||||
**Use for:** Individual developers working on full projects
|
||||
|
||||
#### Full Profile
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y --profile=full
|
||||
```
|
||||
|
||||
**Includes:**
|
||||
|
||||
- All modules
|
||||
- All agents
|
||||
- All workflows
|
||||
|
||||
**Use for:** Maximum flexibility, exploring all BMAD features
|
||||
|
||||
#### Team Profile
|
||||
|
||||
```bash
|
||||
npx bmad-method@alpha install -y --profile=team
|
||||
```
|
||||
|
||||
**Includes:**
|
||||
|
||||
- Modules: core, bmm
|
||||
- Agents: dev, architect, pm, sm, analyst, ux-designer
|
||||
- Workflows: create-product-brief, create-prd, create-architecture, create-epics-and-stories, sprint-planning, create-story, dev-story, code-review, workflow-init
|
||||
|
||||
**Use for:** Team collaboration, full agile workflow
|
||||
|
||||
### Overriding Profile Settings
|
||||
|
||||
```bash
|
||||
# Use minimal profile but add architect agent
|
||||
npx bmad-method@alpha install -y --profile=minimal --agents=dev,architect
|
||||
|
||||
# Use solo-dev profile with custom output folder
|
||||
npx bmad-method@alpha install -y --profile=solo-dev --output-folder=.custom
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "Team not found"
|
||||
|
||||
**Solution:** Check available teams:
|
||||
|
||||
```bash
|
||||
# List available teams in your installation
|
||||
ls src/modules/*/teams/team-*.yaml
|
||||
```
|
||||
|
||||
Available teams depend on installed modules. Ensure you have the required modules.
|
||||
|
||||
### Issue: "Agent not found in manifest"
|
||||
|
||||
**Solution:** The agent name might be incorrect. Check available agents:
|
||||
|
||||
```bash
|
||||
# View all available agents
|
||||
find src/modules -name "*.agent.yaml" -o -name "*-agent.md"
|
||||
```
|
||||
|
||||
Common agent names: `dev`, `architect`, `pm`, `sm`, `analyst`, `ux-designer`, `tech-writer`
|
||||
|
||||
### Issue: "Installation hangs"
|
||||
|
||||
**Solution:** Ensure you're using the `-y` flag for non-interactive mode:
|
||||
|
||||
```bash
|
||||
# Correct
|
||||
npx bmad-method@alpha install -y
|
||||
|
||||
# Incorrect (will wait for input)
|
||||
npx bmad-method@alpha install
|
||||
```
|
||||
|
||||
### Issue: "Permission denied"
|
||||
|
||||
**Solution:** Check file permissions or run with appropriate privileges:
|
||||
|
||||
```bash
|
||||
# Check current directory permissions
|
||||
ls -la
|
||||
|
||||
# Ensure you have write permissions
|
||||
chmod u+w .
|
||||
```
|
||||
|
||||
### Issue: "Invalid skill level"
|
||||
|
||||
**Solution:** Use one of the valid skill levels:
|
||||
|
||||
- `beginner`
|
||||
- `intermediate`
|
||||
- `advanced`
|
||||
|
||||
```bash
|
||||
# Correct
|
||||
npx bmad-method@alpha install -y --skill-level=advanced
|
||||
|
||||
# Incorrect
|
||||
npx bmad-method@alpha install -y --skill-level=expert
|
||||
```
|
||||
|
||||
## Advanced Examples
|
||||
|
||||
### Reproducible Installation
|
||||
|
||||
Save your installation command for reproducibility:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# install-bmad.sh - Reproducible BMAD installation
|
||||
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=ProjectBot \
|
||||
--skill-level=intermediate \
|
||||
--output-folder=_bmad-output \
|
||||
--modules=core,bmm \
|
||||
--agents=dev,architect,pm,analyst \
|
||||
--workflows=create-prd,create-architecture,create-tech-spec,dev-story,code-review \
|
||||
--communication-language=English \
|
||||
--document-language=English
|
||||
```
|
||||
|
||||
### Environment-Based Installation
|
||||
|
||||
Use environment variables for flexibility:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Detect user from environment
|
||||
USER_NAME=${BMAD_USER:-$USER}
|
||||
|
||||
# Detect skill level from environment or default to intermediate
|
||||
SKILL_LEVEL=${BMAD_SKILL_LEVEL:-intermediate}
|
||||
|
||||
npx bmad-method@alpha install -y \
|
||||
--user-name=$USER_NAME \
|
||||
--skill-level=$SKILL_LEVEL \
|
||||
--output-folder=${BMAD_OUTPUT_FOLDER:-_bmad-output}
|
||||
```
|
||||
|
||||
### Conditional Installation
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Install different configurations based on environment
|
||||
|
||||
if [ "$CI" = "true" ]; then
|
||||
# CI environment: minimal installation
|
||||
npx bmad-method@alpha install -y --profile=minimal
|
||||
elif [ "$TEAM_MODE" = "true" ]; then
|
||||
# Team development: full team setup
|
||||
npx bmad-method@alpha install -y --team=fullstack
|
||||
else
|
||||
# Local development: solo-dev profile
|
||||
npx bmad-method@alpha install -y --profile=solo-dev --user-name=$USER
|
||||
fi
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Read the [main README](../README.md) for BMAD overview
|
||||
- Explore [Custom Content Installation](./custom-content-installation.md)
|
||||
- Join the [BMAD Discord](https://discord.gg/gk8jAdXWmj) community
|
||||
|
||||
## Feedback
|
||||
|
||||
Found an issue or have a suggestion? Please report it at:
|
||||
<https://github.com/bmad-code-org/BMAD-METHOD/issues>
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
@ -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!
|
||||
|
|
@ -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!
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -8,11 +8,44 @@ const ui = new UI();
|
|||
|
||||
module.exports = {
|
||||
command: 'install',
|
||||
description: 'Install BMAD Core agents and tools',
|
||||
options: [],
|
||||
description: `Install BMAD Core agents and tools
|
||||
|
||||
Examples:
|
||||
bmad install # Interactive installation
|
||||
bmad install -y # Non-interactive with defaults
|
||||
bmad install -y --user-name=Alice --skill-level=advanced
|
||||
bmad install -y --team=fullstack # Install fullstack team
|
||||
bmad install -y --team=fullstack --agents=+dev # Add dev to fullstack team
|
||||
bmad install -y --agents=dev,architect,pm # Selective agents
|
||||
bmad install -y --profile=minimal # Minimal profile
|
||||
bmad install -y --workflows=create-prd,dev-story # Selective workflows
|
||||
|
||||
Special Values:
|
||||
--agents=all, --agents=none, --agents=minimal
|
||||
--workflows=all, --workflows=none, --workflows=minimal
|
||||
|
||||
Modifiers:
|
||||
--agents=+dev Add agent to team/profile selection
|
||||
--agents=-dev Remove agent from team/profile selection
|
||||
|
||||
Available Teams: fullstack, gamedev
|
||||
Available Profiles: minimal, full, solo-dev, team`,
|
||||
options: [
|
||||
['-y, --non-interactive', 'Run without prompts, use defaults'],
|
||||
['--user-name <name>', 'User name for configuration'],
|
||||
['--skill-level <level>', 'User skill level (beginner, intermediate, advanced)'],
|
||||
['--output-folder <path>', 'Output folder path for BMAD artifacts'],
|
||||
['--modules <list>', 'Comma-separated list of modules to install (e.g., core,bmm)'],
|
||||
['--agents <list>', 'Comma-separated list of agents to install (e.g., dev,architect,pm)'],
|
||||
['--workflows <list>', 'Comma-separated list of workflows to install'],
|
||||
['--team <name>', 'Install predefined team bundle (e.g., fullstack, gamedev)'],
|
||||
['--profile <name>', 'Installation profile (minimal, full, solo-dev)'],
|
||||
['--communication-language <lang>', 'Language for agent communication (default: English)'],
|
||||
['--document-language <lang>', 'Language for generated documents (default: English)'],
|
||||
],
|
||||
action: async (options) => {
|
||||
try {
|
||||
const config = await ui.promptInstall();
|
||||
const config = await ui.promptInstall(options);
|
||||
|
||||
// Handle cancel
|
||||
if (config.actionType === 'cancel') {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const chalk = require('chalk');
|
|||
const inquirer = require('inquirer');
|
||||
const { getProjectRoot, getModulePath } = require('../../../lib/project-root');
|
||||
const { CLIUtils } = require('../../../lib/cli-utils');
|
||||
const { getEnvironmentDefaults, resolveValue } = require('./env-resolver');
|
||||
|
||||
class ConfigCollector {
|
||||
constructor() {
|
||||
|
|
@ -792,6 +793,195 @@ class ConfigCollector {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect configuration for a module in non-interactive mode
|
||||
* @param {string} moduleName - Module name
|
||||
* @param {string} projectDir - Target project directory
|
||||
* @param {Object} cliOptions - CLI options passed by user
|
||||
* @returns {Object} Collected config for the module
|
||||
*/
|
||||
async collectModuleConfigNonInteractive(moduleName, projectDir, cliOptions = {}) {
|
||||
this.currentProjectDir = projectDir;
|
||||
|
||||
// Load existing config if not already loaded
|
||||
if (!this.existingConfig) {
|
||||
await this.loadExistingConfig(projectDir);
|
||||
}
|
||||
|
||||
// Initialize allAnswers if not already initialized
|
||||
if (!this.allAnswers) {
|
||||
this.allAnswers = {};
|
||||
}
|
||||
|
||||
// Get environment defaults
|
||||
const envDefaults = getEnvironmentDefaults();
|
||||
|
||||
// Try to load module config schema
|
||||
let installerConfigPath = null;
|
||||
let moduleConfigPath = null;
|
||||
|
||||
if (this.customModulePaths && this.customModulePaths.has(moduleName)) {
|
||||
const customPath = this.customModulePaths.get(moduleName);
|
||||
installerConfigPath = path.join(customPath, '_module-installer', 'module.yaml');
|
||||
moduleConfigPath = path.join(customPath, 'module.yaml');
|
||||
} else {
|
||||
installerConfigPath = path.join(getModulePath(moduleName), '_module-installer', 'module.yaml');
|
||||
moduleConfigPath = path.join(getModulePath(moduleName), 'module.yaml');
|
||||
}
|
||||
|
||||
// If not found, try to find via module manager
|
||||
if (!(await fs.pathExists(installerConfigPath)) && !(await fs.pathExists(moduleConfigPath))) {
|
||||
const { ModuleManager } = require('../modules/manager');
|
||||
const moduleManager = new ModuleManager();
|
||||
const moduleSourcePath = await moduleManager.findModuleSource(moduleName);
|
||||
|
||||
if (moduleSourcePath) {
|
||||
installerConfigPath = path.join(moduleSourcePath, '_module-installer', 'module.yaml');
|
||||
moduleConfigPath = path.join(moduleSourcePath, 'module.yaml');
|
||||
}
|
||||
}
|
||||
|
||||
let configPath = null;
|
||||
if (await fs.pathExists(moduleConfigPath)) {
|
||||
configPath = moduleConfigPath;
|
||||
} else if (await fs.pathExists(installerConfigPath)) {
|
||||
configPath = installerConfigPath;
|
||||
} else {
|
||||
// No config for this module - use existing if available
|
||||
if (this.existingConfig && this.existingConfig[moduleName]) {
|
||||
this.collectedConfig[moduleName] = { ...this.existingConfig[moduleName] };
|
||||
} else {
|
||||
this.collectedConfig[moduleName] = {};
|
||||
}
|
||||
return this.collectedConfig[moduleName];
|
||||
}
|
||||
|
||||
const configContent = await fs.readFile(configPath, 'utf8');
|
||||
const moduleConfig = yaml.parse(configContent);
|
||||
|
||||
if (!moduleConfig) {
|
||||
this.collectedConfig[moduleName] = {};
|
||||
return this.collectedConfig[moduleName];
|
||||
}
|
||||
|
||||
// Initialize module config
|
||||
if (!this.collectedConfig[moduleName]) {
|
||||
this.collectedConfig[moduleName] = {};
|
||||
}
|
||||
|
||||
// Process each config item
|
||||
const configKeys = Object.keys(moduleConfig).filter((key) => key !== 'prompt');
|
||||
|
||||
for (const key of configKeys) {
|
||||
const item = moduleConfig[key];
|
||||
|
||||
// Skip if not a config object
|
||||
if (!item || typeof item !== 'object') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = null;
|
||||
|
||||
// Resolution order: CLI → ENV → existing → default → hardcoded
|
||||
if (moduleName === 'core') {
|
||||
// Core module has special mappings
|
||||
switch (key) {
|
||||
case 'user_name': {
|
||||
value = resolveValue(cliOptions.userName, null, envDefaults.userName);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'user_skill_level': {
|
||||
value = resolveValue(cliOptions.skillLevel, null, item.default || 'intermediate');
|
||||
|
||||
break;
|
||||
}
|
||||
case 'communication_language': {
|
||||
value = resolveValue(cliOptions.communicationLanguage, null, envDefaults.communicationLanguage);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'document_output_language': {
|
||||
value = resolveValue(cliOptions.documentLanguage, null, envDefaults.documentLanguage);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'output_folder': {
|
||||
value = resolveValue(cliOptions.outputFolder, null, item.default);
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (item.default !== undefined) {
|
||||
value = item.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For other modules, use defaults
|
||||
if (item.default !== undefined) {
|
||||
value = item.default;
|
||||
} else if (this.existingConfig && this.existingConfig[moduleName]) {
|
||||
value = this.existingConfig[moduleName][key];
|
||||
}
|
||||
}
|
||||
|
||||
// Process result template if present
|
||||
let result;
|
||||
if (item.result && typeof item.result === 'string') {
|
||||
result = item.result;
|
||||
if (typeof value === 'string') {
|
||||
result = result.replace('{value}', value);
|
||||
} else if (value !== undefined && value !== null) {
|
||||
result = result.replace('{value}', String(value));
|
||||
}
|
||||
|
||||
// Replace references to other config values
|
||||
result = result.replaceAll(/{([^}]+)}/g, (match, configKey) => {
|
||||
if (configKey === 'project-root' || configKey === 'value') {
|
||||
return match;
|
||||
}
|
||||
|
||||
// Look in collected config
|
||||
let configValue = this.collectedConfig[moduleName]?.[configKey];
|
||||
if (!configValue) {
|
||||
for (const mod of Object.keys(this.collectedConfig)) {
|
||||
if (mod !== '_meta' && this.collectedConfig[mod]?.[configKey]) {
|
||||
configValue = this.collectedConfig[mod][configKey];
|
||||
if (typeof configValue === 'string' && configValue.includes('{project-root}/')) {
|
||||
configValue = configValue.replace('{project-root}/', '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return configValue || match;
|
||||
});
|
||||
} else if (item.result) {
|
||||
result = value;
|
||||
} else {
|
||||
result = value;
|
||||
}
|
||||
|
||||
// Store the result
|
||||
this.collectedConfig[moduleName][key] = result;
|
||||
this.allAnswers[`${moduleName}_${key}`] = result;
|
||||
}
|
||||
|
||||
// Copy existing values for fields not in schema
|
||||
if (this.existingConfig && this.existingConfig[moduleName]) {
|
||||
for (const [key, value] of Object.entries(this.existingConfig[moduleName])) {
|
||||
if (this.collectedConfig[moduleName][key] === undefined) {
|
||||
this.collectedConfig[moduleName][key] = value;
|
||||
this.allAnswers[`${moduleName}_${key}`] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.collectedConfig[moduleName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace placeholders in a string with collected config values
|
||||
* @param {string} str - String with placeholders
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
const os = require('node:os');
|
||||
|
||||
/**
|
||||
* Environment Variable Resolver
|
||||
*
|
||||
* Resolves configuration values from environment variables
|
||||
* with fallbacks to system defaults.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get user name from environment variables
|
||||
* Tries USER, USERNAME, LOGNAME in order, falls back to system username or 'User'
|
||||
* @returns {string} User name
|
||||
*/
|
||||
function getUserName() {
|
||||
// Try common environment variables
|
||||
const envUser = process.env.USER || process.env.USERNAME || process.env.LOGNAME;
|
||||
|
||||
if (envUser) {
|
||||
return envUser;
|
||||
}
|
||||
|
||||
// Try Node.js os.userInfo()
|
||||
try {
|
||||
const userInfo = os.userInfo();
|
||||
if (userInfo.username) {
|
||||
return userInfo.username;
|
||||
}
|
||||
} catch {
|
||||
// os.userInfo() can fail in some environments
|
||||
}
|
||||
|
||||
// Final fallback
|
||||
return 'User';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system language from environment variables
|
||||
* Tries LANG, LC_ALL, falls back to 'English'
|
||||
* @returns {string} Language name
|
||||
*/
|
||||
function getSystemLanguage() {
|
||||
const lang = process.env.LANG || process.env.LC_ALL;
|
||||
|
||||
if (!lang) {
|
||||
return 'English';
|
||||
}
|
||||
|
||||
// Parse language from locale string (e.g., 'en_US.UTF-8' -> 'English')
|
||||
const langCode = lang.split('_')[0].toLowerCase();
|
||||
|
||||
// Map common language codes to full names
|
||||
const languageMap = {
|
||||
en: 'English',
|
||||
es: 'Spanish',
|
||||
fr: 'French',
|
||||
de: 'German',
|
||||
it: 'Italian',
|
||||
pt: 'Portuguese',
|
||||
ru: 'Russian',
|
||||
ja: 'Japanese',
|
||||
zh: 'Chinese',
|
||||
ko: 'Korean',
|
||||
ar: 'Arabic',
|
||||
hi: 'Hindi',
|
||||
};
|
||||
|
||||
return languageMap[langCode] || 'English';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get home directory from environment
|
||||
* @returns {string} Home directory path
|
||||
*/
|
||||
function getHomeDirectory() {
|
||||
return process.env.HOME || process.env.USERPROFILE || os.homedir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a config value with priority: CLI > ENV > default
|
||||
* @param {*} cliValue - Value from CLI argument
|
||||
* @param {string} envVar - Environment variable name to check
|
||||
* @param {*} defaultValue - Default value if neither CLI nor ENV is set
|
||||
* @returns {*} Resolved value
|
||||
*/
|
||||
function resolveValue(cliValue, envVar, defaultValue) {
|
||||
// CLI value has highest priority
|
||||
if (cliValue !== undefined && cliValue !== null) {
|
||||
return cliValue;
|
||||
}
|
||||
|
||||
// Try environment variable
|
||||
if (envVar && process.env[envVar]) {
|
||||
return process.env[envVar];
|
||||
}
|
||||
|
||||
// Use default
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all environment-based defaults
|
||||
* @returns {Object} Default config values from environment
|
||||
*/
|
||||
function getEnvironmentDefaults() {
|
||||
return {
|
||||
userName: getUserName(),
|
||||
communicationLanguage: getSystemLanguage(),
|
||||
documentLanguage: getSystemLanguage(),
|
||||
homeDirectory: getHomeDirectory(),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getUserName,
|
||||
getSystemLanguage,
|
||||
getHomeDirectory,
|
||||
resolveValue,
|
||||
getEnvironmentDefaults,
|
||||
};
|
||||
|
|
@ -1041,6 +1041,9 @@ class Installer {
|
|||
const manifestStats = await manifestGen.generateManifests(bmadDir, allModulesForManifest, [...this.installedFiles], {
|
||||
ides: config.ides || [],
|
||||
preservedModules: modulesForCsvPreserve, // Scan these from installed bmad/ dir
|
||||
selectedAgents: config.cliOptions?.agents || null,
|
||||
selectedWorkflows: config.cliOptions?.workflows || null,
|
||||
installMode: config.cliOptions ? 'non-interactive' : 'interactive',
|
||||
});
|
||||
|
||||
// Custom modules are now included in the main modules list - no separate tracking needed
|
||||
|
|
|
|||
|
|
@ -65,11 +65,20 @@ class ManifestGenerator {
|
|||
// Filter out any undefined/null values from IDE list
|
||||
this.selectedIdes = resolvedIdes.filter((ide) => ide && typeof ide === 'string');
|
||||
|
||||
// Get filtering options from options
|
||||
const selectedAgents = options.selectedAgents || null;
|
||||
const selectedWorkflows = options.selectedWorkflows || null;
|
||||
|
||||
// Store installation mode and options for manifest
|
||||
this.installMode = options.installMode || 'interactive';
|
||||
this.selectedAgentsList = selectedAgents;
|
||||
this.selectedWorkflowsList = selectedWorkflows;
|
||||
|
||||
// Collect workflow data
|
||||
await this.collectWorkflows(selectedModules);
|
||||
await this.collectWorkflows(selectedModules, selectedWorkflows);
|
||||
|
||||
// Collect agent data - use updatedModules which includes all installed modules
|
||||
await this.collectAgents(this.updatedModules);
|
||||
await this.collectAgents(this.updatedModules, selectedAgents);
|
||||
|
||||
// Collect task data
|
||||
await this.collectTasks(this.updatedModules);
|
||||
|
|
@ -100,8 +109,10 @@ class ManifestGenerator {
|
|||
/**
|
||||
* Collect all workflows from core and selected modules
|
||||
* Scans the INSTALLED bmad directory, not the source
|
||||
* @param {Array} selectedModules - Modules to scan for workflows
|
||||
* @param {Array|null} selectedWorkflows - Optional array of workflow names to filter by
|
||||
*/
|
||||
async collectWorkflows(selectedModules) {
|
||||
async collectWorkflows(selectedModules, selectedWorkflows = null) {
|
||||
this.workflows = [];
|
||||
|
||||
// Use updatedModules which already includes deduplicated 'core' + selectedModules
|
||||
|
|
@ -113,6 +124,50 @@ class ManifestGenerator {
|
|||
this.workflows.push(...moduleWorkflows);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply filtering if selectedWorkflows is provided
|
||||
if (selectedWorkflows && Array.isArray(selectedWorkflows) && selectedWorkflows.length > 0) {
|
||||
this.workflows = this.filterWorkflows(this.workflows, selectedWorkflows);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter workflows by name matching (supports wildcards)
|
||||
* @param {Array} workflows - Array of workflow objects
|
||||
* @param {Array} selectedWorkflows - Array of workflow names to filter by (supports * wildcard)
|
||||
* @returns {Array} Filtered workflows
|
||||
*/
|
||||
filterWorkflows(workflows, selectedWorkflows) {
|
||||
if (!selectedWorkflows || selectedWorkflows.length === 0) {
|
||||
return workflows;
|
||||
}
|
||||
|
||||
// Check for special values
|
||||
if (selectedWorkflows.includes('all')) {
|
||||
return workflows;
|
||||
}
|
||||
if (selectedWorkflows.includes('none')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return workflows.filter((workflow) => {
|
||||
const workflowName = workflow.name;
|
||||
|
||||
return selectedWorkflows.some((pattern) => {
|
||||
// Exact match
|
||||
if (pattern === workflowName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wildcard matching: create-* matches create-prd, create-tech-spec, etc.
|
||||
if (pattern.includes('*')) {
|
||||
const regex = new RegExp('^' + pattern.replaceAll('*', '.*') + '$');
|
||||
return regex.test(workflowName);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -197,8 +252,10 @@ class ManifestGenerator {
|
|||
/**
|
||||
* Collect all agents from core and selected modules
|
||||
* Scans the INSTALLED bmad directory, not the source
|
||||
* @param {Array} selectedModules - Modules to scan for agents
|
||||
* @param {Array|null} selectedAgents - Optional array of agent names to filter by
|
||||
*/
|
||||
async collectAgents(selectedModules) {
|
||||
async collectAgents(selectedModules, selectedAgents = null) {
|
||||
this.agents = [];
|
||||
|
||||
// Use updatedModules which already includes deduplicated 'core' + selectedModules
|
||||
|
|
@ -224,6 +281,50 @@ class ManifestGenerator {
|
|||
this.agents.push(...standaloneAgents);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply filtering if selectedAgents is provided
|
||||
if (selectedAgents && Array.isArray(selectedAgents) && selectedAgents.length > 0) {
|
||||
this.agents = this.filterAgents(this.agents, selectedAgents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter agents by name matching (supports wildcards)
|
||||
* @param {Array} agents - Array of agent objects
|
||||
* @param {Array} selectedAgents - Array of agent names to filter by (supports * wildcard)
|
||||
* @returns {Array} Filtered agents
|
||||
*/
|
||||
filterAgents(agents, selectedAgents) {
|
||||
if (!selectedAgents || selectedAgents.length === 0) {
|
||||
return agents;
|
||||
}
|
||||
|
||||
// Check for special values
|
||||
if (selectedAgents.includes('all')) {
|
||||
return agents;
|
||||
}
|
||||
if (selectedAgents.includes('none')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return agents.filter((agent) => {
|
||||
const agentName = agent.name;
|
||||
|
||||
return selectedAgents.some((pattern) => {
|
||||
// Exact match
|
||||
if (pattern === agentName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wildcard matching: dev* matches dev, dev-story, etc.
|
||||
if (pattern.includes('*')) {
|
||||
const regex = new RegExp('^' + pattern.replaceAll('*', '.*') + '$');
|
||||
return regex.test(agentName);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -462,11 +563,20 @@ class ManifestGenerator {
|
|||
version: packageJson.version,
|
||||
installDate: new Date().toISOString(),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
installMode: this.installMode || 'interactive',
|
||||
},
|
||||
modules: this.modules, // Include ALL modules (standard and custom)
|
||||
ides: this.selectedIdes,
|
||||
};
|
||||
|
||||
// Add selective installation info if filters were applied
|
||||
if (this.selectedAgentsList && this.selectedAgentsList.length > 0) {
|
||||
manifest.selectedAgents = this.selectedAgentsList;
|
||||
}
|
||||
if (this.selectedWorkflowsList && this.selectedWorkflowsList.length > 0) {
|
||||
manifest.selectedWorkflows = this.selectedWorkflowsList;
|
||||
}
|
||||
|
||||
// Clean the manifest to remove any non-serializable values
|
||||
const cleanManifest = structuredClone(manifest);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
const { getProfile } = require('../profiles/definitions');
|
||||
|
||||
/**
|
||||
* CLI Options Parser
|
||||
*
|
||||
* Parses and normalizes CLI options for non-interactive installation.
|
||||
* Handles profiles, comma-separated lists, special values, and validation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse comma-separated list into array
|
||||
* @param {string|undefined} value - Comma-separated string or undefined
|
||||
* @returns {string[]|null} Array of trimmed values or null if undefined
|
||||
*/
|
||||
function parseList(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return value
|
||||
.split(',')
|
||||
.map((item) => item.trim())
|
||||
.filter((item) => item.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if value is a special keyword
|
||||
* @param {string|string[]|null} value - Value to check
|
||||
* @returns {boolean} True if special keyword (all, none, minimal)
|
||||
*/
|
||||
function isSpecialValue(value) {
|
||||
if (Array.isArray(value) && value.length === 1) {
|
||||
value = value[0];
|
||||
}
|
||||
|
||||
return value === 'all' || value === 'none' || value === 'minimal';
|
||||
}
|
||||
|
||||
/**
|
||||
* Separate additive (+) and subtractive (-) modifiers from list
|
||||
* @param {string[]} list - Array of items, some may have +/- prefix
|
||||
* @returns {Object} { base: [], add: [], remove: [] }
|
||||
*/
|
||||
function separateModifiers(list) {
|
||||
const result = {
|
||||
base: [],
|
||||
add: [],
|
||||
remove: [],
|
||||
};
|
||||
|
||||
if (!list || !Array.isArray(list)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const item of list) {
|
||||
if (item.startsWith('+')) {
|
||||
result.add.push(item.slice(1));
|
||||
} else if (item.startsWith('-')) {
|
||||
result.remove.push(item.slice(1));
|
||||
} else {
|
||||
result.base.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply modifiers to a base list (additive/subtractive)
|
||||
* @param {string[]} baseList - Base list of items
|
||||
* @param {string[]} add - Items to add
|
||||
* @param {string[]} remove - Items to remove
|
||||
* @returns {string[]} Modified list
|
||||
*/
|
||||
function applyModifiers(baseList, add = [], remove = []) {
|
||||
let result = [...baseList];
|
||||
|
||||
// Add items
|
||||
for (const item of add) {
|
||||
if (!result.includes(item)) {
|
||||
result.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove items
|
||||
for (const item of remove) {
|
||||
result = result.filter((i) => i !== item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and normalize CLI options
|
||||
* @param {Object} cliOptions - Raw CLI options from commander
|
||||
* @returns {Object} Normalized options
|
||||
*/
|
||||
function parseOptions(cliOptions) {
|
||||
const normalized = {
|
||||
nonInteractive: cliOptions.nonInteractive || false,
|
||||
userName: cliOptions.userName,
|
||||
skillLevel: cliOptions.skillLevel,
|
||||
outputFolder: cliOptions.outputFolder,
|
||||
communicationLanguage: cliOptions.communicationLanguage,
|
||||
documentLanguage: cliOptions.documentLanguage,
|
||||
modules: parseList(cliOptions.modules),
|
||||
agents: parseList(cliOptions.agents),
|
||||
workflows: parseList(cliOptions.workflows),
|
||||
team: cliOptions.team,
|
||||
profile: cliOptions.profile,
|
||||
};
|
||||
|
||||
// Expand profile if provided
|
||||
if (normalized.profile) {
|
||||
const profile = getProfile(normalized.profile);
|
||||
if (!profile) {
|
||||
throw new Error(`Unknown profile: ${normalized.profile}. Valid profiles: minimal, full, solo-dev, team`);
|
||||
}
|
||||
|
||||
// Use profile values as defaults when CLI options not provided
|
||||
// Ensure strings like 'all' are wrapped in arrays for consistency
|
||||
if (!normalized.modules) {
|
||||
normalized.modules = Array.isArray(profile.modules) ? profile.modules : [profile.modules];
|
||||
}
|
||||
if (!normalized.agents) {
|
||||
normalized.agents = Array.isArray(profile.agents) ? profile.agents : [profile.agents];
|
||||
}
|
||||
if (!normalized.workflows) {
|
||||
normalized.workflows = Array.isArray(profile.workflows) ? profile.workflows : [profile.workflows];
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate parsed options for conflicts and errors
|
||||
* @param {Object} options - Parsed options
|
||||
* @returns {Object} { valid: boolean, errors: string[] }
|
||||
*/
|
||||
function validateOptions(options) {
|
||||
const errors = [];
|
||||
|
||||
// Validate skill level
|
||||
if (options.skillLevel) {
|
||||
const validLevels = ['beginner', 'intermediate', 'advanced'];
|
||||
if (!validLevels.includes(options.skillLevel.toLowerCase())) {
|
||||
errors.push(`Invalid skill level: ${options.skillLevel}. Valid values: beginner, intermediate, advanced`);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate profile
|
||||
if (options.profile) {
|
||||
const validProfiles = ['minimal', 'full', 'solo-dev', 'team'];
|
||||
if (!validProfiles.includes(options.profile.toLowerCase())) {
|
||||
errors.push(`Invalid profile: ${options.profile}. Valid values: minimal, full, solo-dev, team`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for empty selections
|
||||
if (options.agents && Array.isArray(options.agents) && options.agents.length === 0) {
|
||||
errors.push('Agents list cannot be empty');
|
||||
}
|
||||
|
||||
if (options.workflows && Array.isArray(options.workflows) && options.workflows.length === 0) {
|
||||
errors.push('Workflows list cannot be empty');
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parseList,
|
||||
isSpecialValue,
|
||||
separateModifiers,
|
||||
applyModifiers,
|
||||
parseOptions,
|
||||
validateOptions,
|
||||
};
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* Installation Profile Definitions
|
||||
*
|
||||
* Profiles are pre-defined combinations of modules, agents, and workflows
|
||||
* for common use cases. Users can select a profile with --profile=<name>
|
||||
* and override specific selections with CLI flags.
|
||||
*/
|
||||
|
||||
const PROFILES = {
|
||||
minimal: {
|
||||
name: 'minimal',
|
||||
description: 'Minimal installation - core + dev agent + essential workflows',
|
||||
modules: ['core'],
|
||||
agents: ['dev'],
|
||||
workflows: ['create-tech-spec', 'quick-dev'],
|
||||
},
|
||||
|
||||
full: {
|
||||
name: 'full',
|
||||
description: 'Full installation - all modules, agents, and workflows',
|
||||
modules: 'all',
|
||||
agents: 'all',
|
||||
workflows: 'all',
|
||||
},
|
||||
|
||||
'solo-dev': {
|
||||
name: 'solo-dev',
|
||||
description: 'Single developer setup - dev tools and planning workflows',
|
||||
modules: ['core', 'bmm'],
|
||||
agents: ['dev', 'architect', 'analyst', 'tech-writer'],
|
||||
workflows: ['create-tech-spec', 'quick-dev', 'dev-story', 'code-review', 'create-prd', 'create-architecture'],
|
||||
},
|
||||
|
||||
team: {
|
||||
name: 'team',
|
||||
description: 'Team collaboration setup - planning and execution workflows',
|
||||
modules: ['core', 'bmm'],
|
||||
agents: ['dev', 'architect', 'pm', 'sm', 'analyst', 'ux-designer'],
|
||||
workflows: [
|
||||
'create-product-brief',
|
||||
'create-prd',
|
||||
'create-architecture',
|
||||
'create-epics-and-stories',
|
||||
'sprint-planning',
|
||||
'create-story',
|
||||
'dev-story',
|
||||
'code-review',
|
||||
'workflow-init',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a profile by name
|
||||
* @param {string} name - Profile name (minimal, full, solo-dev, team)
|
||||
* @returns {Object|null} Profile definition or null if not found
|
||||
*/
|
||||
function getProfile(name) {
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const profile = PROFILES[name.toLowerCase()];
|
||||
if (!profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return a copy to prevent mutation
|
||||
return { ...profile };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available profile names
|
||||
* @returns {string[]} Array of profile names
|
||||
*/
|
||||
function getProfileNames() {
|
||||
return Object.keys(PROFILES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile descriptions for help text
|
||||
* @returns {Object} Map of profile name to description
|
||||
*/
|
||||
function getProfileDescriptions() {
|
||||
const descriptions = {};
|
||||
for (const [name, profile] of Object.entries(PROFILES)) {
|
||||
descriptions[name] = profile.description;
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getProfile,
|
||||
getProfileNames,
|
||||
getProfileDescriptions,
|
||||
};
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const yaml = require('yaml');
|
||||
const { glob } = require('glob');
|
||||
|
||||
/**
|
||||
* Team Loader
|
||||
*
|
||||
* Discovers and loads team bundles from module definitions.
|
||||
* Teams are predefined collections of agents and workflows for common use cases.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Discover all available teams across modules
|
||||
* @param {string} projectRoot - Project root directory
|
||||
* @returns {Promise<Object[]>} Array of team metadata { name, module, path, description }
|
||||
*/
|
||||
async function discoverTeams(projectRoot) {
|
||||
const teams = [];
|
||||
const pattern = path.join(projectRoot, 'src/modules/*/teams/team-*.yaml');
|
||||
|
||||
try {
|
||||
const files = await glob(pattern, { absolute: true });
|
||||
|
||||
for (const filePath of files) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const teamData = yaml.parse(content);
|
||||
|
||||
// Extract team name from filename (team-fullstack.yaml -> fullstack)
|
||||
const filename = path.basename(filePath);
|
||||
const teamName = filename.replace(/^team-/, '').replace(/\.yaml$/, '');
|
||||
|
||||
// Extract module name from path
|
||||
const moduleName = path.basename(path.dirname(path.dirname(filePath)));
|
||||
|
||||
teams.push({
|
||||
name: teamName,
|
||||
module: moduleName,
|
||||
path: filePath,
|
||||
description: teamData.bundle?.description || 'No description',
|
||||
bundleName: teamData.bundle?.name || teamName,
|
||||
icon: teamData.bundle?.icon || '👥',
|
||||
});
|
||||
} catch (error) {
|
||||
// Skip files that can't be parsed
|
||||
console.warn(`Warning: Could not parse team file ${filePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return teams;
|
||||
} catch {
|
||||
// If glob fails, return empty array
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a specific team by name
|
||||
* @param {string} teamName - Team name (e.g., 'fullstack', 'gamedev')
|
||||
* @param {string} projectRoot - Project root directory
|
||||
* @returns {Promise<Object>} Team data with metadata
|
||||
*/
|
||||
async function loadTeam(teamName, projectRoot) {
|
||||
if (!teamName) {
|
||||
throw new Error('Team name is required');
|
||||
}
|
||||
|
||||
// Discover all teams
|
||||
const teams = await discoverTeams(projectRoot);
|
||||
|
||||
// Find matching team
|
||||
const team = teams.find((t) => t.name.toLowerCase() === teamName.toLowerCase());
|
||||
|
||||
if (!team) {
|
||||
// Provide helpful error with suggestions
|
||||
const availableTeams = teams.map((t) => t.name).join(', ');
|
||||
throw new Error(`Team '${teamName}' not found. Available teams: ${availableTeams || 'none'}`);
|
||||
}
|
||||
|
||||
// Load full team definition
|
||||
const content = fs.readFileSync(team.path, 'utf8');
|
||||
const teamData = yaml.parse(content);
|
||||
|
||||
return {
|
||||
name: team.name,
|
||||
module: team.module,
|
||||
description: team.description,
|
||||
bundleName: team.bundleName,
|
||||
icon: team.icon,
|
||||
agents: teamData.agents || [],
|
||||
workflows: teamData.workflows || [],
|
||||
party: teamData.party,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand team definition to full agents and workflows list
|
||||
* @param {string} teamName - Team name
|
||||
* @param {string} projectRoot - Project root directory
|
||||
* @returns {Promise<Object>} { agents: [], workflows: [], module: string }
|
||||
*/
|
||||
async function expandTeam(teamName, projectRoot) {
|
||||
const team = await loadTeam(teamName, projectRoot);
|
||||
|
||||
return {
|
||||
agents: team.agents || [],
|
||||
workflows: team.workflows || [],
|
||||
module: team.module,
|
||||
description: team.description,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply modifiers to team selections (additive/subtractive)
|
||||
* @param {Object} team - Team expansion result
|
||||
* @param {string[]} agentModifiers - Agent modifiers (+agent, -agent)
|
||||
* @param {string[]} workflowModifiers - Workflow modifiers (+workflow, -workflow)
|
||||
* @returns {Object} Modified team with updated agents/workflows
|
||||
*/
|
||||
function applyTeamModifiers(team, agentModifiers = [], workflowModifiers = []) {
|
||||
const result = {
|
||||
...team,
|
||||
agents: [...team.agents],
|
||||
workflows: [...team.workflows],
|
||||
};
|
||||
|
||||
// Parse and apply agent modifiers
|
||||
for (const modifier of agentModifiers) {
|
||||
if (modifier.startsWith('+')) {
|
||||
const agent = modifier.slice(1);
|
||||
if (!result.agents.includes(agent)) {
|
||||
result.agents.push(agent);
|
||||
}
|
||||
} else if (modifier.startsWith('-')) {
|
||||
const agent = modifier.slice(1);
|
||||
result.agents = result.agents.filter((a) => a !== agent);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse and apply workflow modifiers
|
||||
for (const modifier of workflowModifiers) {
|
||||
if (modifier.startsWith('+')) {
|
||||
const workflow = modifier.slice(1);
|
||||
if (!result.workflows.includes(workflow)) {
|
||||
result.workflows.push(workflow);
|
||||
}
|
||||
} else if (modifier.startsWith('-')) {
|
||||
const workflow = modifier.slice(1);
|
||||
result.workflows = result.workflows.filter((w) => w !== workflow);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get team descriptions for help text
|
||||
* @param {string} projectRoot - Project root directory
|
||||
* @returns {Promise<Object>} Map of team name to description
|
||||
*/
|
||||
async function getTeamDescriptions(projectRoot) {
|
||||
const teams = await discoverTeams(projectRoot);
|
||||
const descriptions = {};
|
||||
|
||||
for (const team of teams) {
|
||||
descriptions[team.name] = team.description;
|
||||
}
|
||||
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
discoverTeams,
|
||||
loadTeam,
|
||||
expandTeam,
|
||||
applyTeamModifiers,
|
||||
getTeamDescriptions,
|
||||
};
|
||||
|
|
@ -12,9 +12,15 @@ const { CustomHandler } = require('../installers/lib/custom/handler');
|
|||
class UI {
|
||||
/**
|
||||
* Prompt for installation configuration
|
||||
* @param {Object} cliOptions - CLI options for non-interactive mode
|
||||
* @returns {Object} Installation configuration
|
||||
*/
|
||||
async promptInstall() {
|
||||
async promptInstall(cliOptions = {}) {
|
||||
// Handle non-interactive mode
|
||||
if (cliOptions.nonInteractive) {
|
||||
return await this.buildNonInteractiveConfig(cliOptions);
|
||||
}
|
||||
|
||||
CLIUtils.displayLogo();
|
||||
|
||||
// Display changelog link
|
||||
|
|
@ -1457,6 +1463,139 @@ class UI {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build non-interactive installation configuration
|
||||
* @param {Object} cliOptions - CLI options
|
||||
* @returns {Object} Installation configuration
|
||||
*/
|
||||
async buildNonInteractiveConfig(cliOptions) {
|
||||
const { parseOptions } = require('../installers/lib/core/options-parser');
|
||||
const { expandTeam, applyTeamModifiers } = require('../installers/lib/teams/team-loader');
|
||||
const { getProjectRoot } = require('./project-root');
|
||||
const { getEnvironmentDefaults } = require('../installers/lib/core/env-resolver');
|
||||
|
||||
console.log(chalk.cyan('🤖 Running non-interactive installation...\n'));
|
||||
|
||||
// Parse and normalize options
|
||||
const options = parseOptions(cliOptions);
|
||||
const envDefaults = getEnvironmentDefaults();
|
||||
|
||||
// Determine directory
|
||||
const directory = process.cwd();
|
||||
|
||||
// Check for existing installation
|
||||
const { Installer } = require('../installers/lib/core/installer');
|
||||
const installer = new Installer();
|
||||
const { bmadDir, hasExistingInstall } = await installer.findBmadDir(directory);
|
||||
const actionType = hasExistingInstall ? 'update' : 'install';
|
||||
|
||||
console.log(chalk.dim(` Directory: ${directory}`));
|
||||
console.log(chalk.dim(` Action: ${actionType === 'install' ? 'New installation' : 'Update existing installation'}\n`));
|
||||
|
||||
// Determine modules to install
|
||||
let selectedModules = [];
|
||||
|
||||
if (options.team) {
|
||||
// Team-based installation
|
||||
console.log(chalk.cyan(`📦 Loading team: ${options.team}...`));
|
||||
try {
|
||||
const projectRoot = getProjectRoot();
|
||||
let teamExpansion = await expandTeam(options.team, projectRoot);
|
||||
|
||||
// Apply modifiers if present
|
||||
if (options.agents || options.workflows) {
|
||||
const { separateModifiers } = require('../installers/lib/core/options-parser');
|
||||
const agentMods = options.agents ? separateModifiers(options.agents) : { base: [], add: [], remove: [] };
|
||||
const workflowMods = options.workflows ? separateModifiers(options.workflows) : { base: [], add: [], remove: [] };
|
||||
|
||||
// If base is provided, replace team selections completely
|
||||
if (agentMods.base.length > 0) {
|
||||
teamExpansion.agents = agentMods.base;
|
||||
}
|
||||
if (workflowMods.base.length > 0) {
|
||||
teamExpansion.workflows = workflowMods.base;
|
||||
}
|
||||
|
||||
// Apply modifiers
|
||||
teamExpansion = applyTeamModifiers(
|
||||
teamExpansion,
|
||||
[...agentMods.add.map((a) => `+${a}`), ...agentMods.remove.map((a) => `-${a}`)],
|
||||
[...workflowMods.add.map((w) => `+${w}`), ...workflowMods.remove.map((w) => `-${w}`)],
|
||||
);
|
||||
}
|
||||
|
||||
options.agents = teamExpansion.agents;
|
||||
options.workflows = teamExpansion.workflows;
|
||||
|
||||
// Determine module from team
|
||||
if (teamExpansion.module && !selectedModules.includes(teamExpansion.module)) {
|
||||
selectedModules.push(teamExpansion.module);
|
||||
}
|
||||
|
||||
console.log(chalk.green(` ✓ Team loaded: ${options.team}`));
|
||||
console.log(chalk.dim(` Agents: ${teamExpansion.agents.join(', ')}`));
|
||||
if (teamExpansion.workflows && teamExpansion.workflows.length > 0) {
|
||||
console.log(chalk.dim(` Workflows: ${teamExpansion.workflows.join(', ')}`));
|
||||
}
|
||||
console.log('');
|
||||
} catch (error) {
|
||||
console.error(chalk.red(` ✗ Failed to load team: ${error.message}`));
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (options.modules) {
|
||||
// Module-based installation
|
||||
if (options.modules === 'all' || (Array.isArray(options.modules) && options.modules.includes('all'))) {
|
||||
selectedModules = ['bmm', 'bmbb', 'cis', 'bmgd'];
|
||||
} else if (Array.isArray(options.modules)) {
|
||||
selectedModules = options.modules.filter((m) => m !== 'core');
|
||||
}
|
||||
} else if (options.profile) {
|
||||
// Profile-based installation
|
||||
const { getProfile } = require('../installers/lib/profiles/definitions');
|
||||
const profile = getProfile(options.profile);
|
||||
if (profile.modules === 'all' || (Array.isArray(profile.modules) && profile.modules.includes('all'))) {
|
||||
selectedModules = ['bmm', 'bmbb', 'cis', 'bmgd'];
|
||||
} else if (Array.isArray(profile.modules)) {
|
||||
selectedModules = profile.modules.filter((m) => m !== 'core');
|
||||
}
|
||||
} else {
|
||||
// Default: install bmm
|
||||
selectedModules = ['bmm'];
|
||||
}
|
||||
|
||||
console.log(chalk.cyan(`📦 Modules: ${selectedModules.length > 0 ? selectedModules.join(', ') : 'core only'}\n`));
|
||||
|
||||
// Build core configuration
|
||||
const coreConfig = {
|
||||
user_name: options.userName || envDefaults.userName,
|
||||
user_skill_level: options.skillLevel || 'intermediate',
|
||||
communication_language: options.communicationLanguage || envDefaults.communicationLanguage,
|
||||
document_output_language: options.documentLanguage || envDefaults.documentLanguage,
|
||||
output_folder: options.outputFolder || '_bmad-output',
|
||||
};
|
||||
|
||||
console.log(chalk.cyan('⚙️ Configuration:'));
|
||||
console.log(chalk.dim(` User: ${coreConfig.user_name}`));
|
||||
console.log(chalk.dim(` Skill Level: ${coreConfig.user_skill_level}`));
|
||||
console.log(chalk.dim(` Language: ${coreConfig.communication_language}\n`));
|
||||
|
||||
// Return installation configuration
|
||||
return {
|
||||
actionType,
|
||||
directory,
|
||||
installCore: true,
|
||||
modules: selectedModules,
|
||||
ides: ['claude-code'], // Default to Claude Code for non-interactive
|
||||
skipIde: false,
|
||||
coreConfig,
|
||||
customContent: { hasCustomContent: false },
|
||||
enableAgentVibes: false,
|
||||
agentVibesInstalled: false,
|
||||
// Pass through CLI options for downstream use
|
||||
cliOptions: options,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { UI };
|
||||
|
|
|
|||
|
|
@ -0,0 +1,178 @@
|
|||
#!/bin/bash
|
||||
# Test script for non-interactive BMAD installation
|
||||
# Tests various CLI options and validates installation
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
TEST_DIR="/tmp/bmad-test-$(date +%s)"
|
||||
|
||||
echo "🧪 BMAD Non-Interactive Installation Test Suite"
|
||||
echo "================================================"
|
||||
echo "Test directory: $TEST_DIR"
|
||||
echo ""
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Track test results
|
||||
TESTS_PASSED=0
|
||||
TESTS_FAILED=0
|
||||
|
||||
# Helper function to run a test
|
||||
run_test() {
|
||||
local test_name="$1"
|
||||
local test_dir="$TEST_DIR/$test_name"
|
||||
shift
|
||||
|
||||
echo -e "${YELLOW}▶ Running: $test_name${NC}"
|
||||
mkdir -p "$test_dir"
|
||||
cd "$test_dir"
|
||||
|
||||
if "$@"; then
|
||||
echo -e "${GREEN}✓ PASSED: $test_name${NC}"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}✗ FAILED: $test_name${NC}"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Helper to verify installation
|
||||
verify_installation() {
|
||||
local dir="$1"
|
||||
local expected_agents="$2" # comma-separated list
|
||||
local expected_workflows="$3" # comma-separated list
|
||||
|
||||
# Check _bmad directory exists
|
||||
if [ ! -d "$dir/_bmad" ]; then
|
||||
echo "❌ _bmad directory not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check manifest exists
|
||||
if [ ! -f "$dir/_bmad/_config/manifest.yaml" ]; then
|
||||
echo "❌ manifest.yaml not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check agents CSV if expected agents provided
|
||||
if [ -n "$expected_agents" ]; then
|
||||
if [ ! -f "$dir/_bmad/_config/agents.csv" ]; then
|
||||
echo "❌ agents.csv not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
IFS=',' read -ra AGENTS <<< "$expected_agents"
|
||||
for agent in "${AGENTS[@]}"; do
|
||||
if ! grep -q "$agent" "$dir/_bmad/_config/agents.csv"; then
|
||||
echo "❌ Agent '$agent' not found in agents.csv"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Check workflows CSV if expected workflows provided
|
||||
if [ -n "$expected_workflows" ]; then
|
||||
if [ ! -f "$dir/_bmad/_config/workflows.csv" ]; then
|
||||
echo "❌ workflows.csv not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
IFS=',' read -ra WORKFLOWS <<< "$expected_workflows"
|
||||
for workflow in "${WORKFLOWS[@]}"; do
|
||||
if ! grep -q "$workflow" "$dir/_bmad/_config/workflows.csv"; then
|
||||
echo "❌ Workflow '$workflow' not found in workflows.csv"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "✓ Installation verified"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Test 1: Minimal non-interactive installation
|
||||
run_test "test-01-minimal-install" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y
|
||||
verify_installation . '' ''
|
||||
"
|
||||
|
||||
# Test 2: Non-interactive with custom user name
|
||||
run_test "test-02-custom-user" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y --user-name=TestUser
|
||||
verify_installation . '' ''
|
||||
grep -q 'user_name: TestUser' _bmad/core/config.yaml
|
||||
"
|
||||
|
||||
# Test 3: Selective agent installation
|
||||
run_test "test-03-selective-agents" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y --agents=dev,architect
|
||||
verify_installation . 'dev,architect' ''
|
||||
"
|
||||
|
||||
# Test 4: Selective workflow installation
|
||||
run_test "test-04-selective-workflows" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y --workflows=create-prd,create-tech-spec
|
||||
verify_installation . '' 'create-prd,create-tech-spec'
|
||||
"
|
||||
|
||||
# Test 5: Team-based installation (fullstack)
|
||||
run_test "test-05-team-fullstack" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y --team=fullstack
|
||||
verify_installation . 'analyst,architect,pm,sm,ux-designer' ''
|
||||
"
|
||||
|
||||
# Test 6: Profile-based installation (minimal)
|
||||
run_test "test-06-profile-minimal" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y --profile=minimal
|
||||
verify_installation . 'dev' 'create-tech-spec,quick-dev'
|
||||
"
|
||||
|
||||
# Test 7: Multiple CLI options
|
||||
run_test "test-07-multiple-options" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y \
|
||||
--user-name=FullTest \
|
||||
--skill-level=advanced \
|
||||
--output-folder=.output \
|
||||
--agents=dev,architect
|
||||
verify_installation . 'dev,architect' ''
|
||||
grep -q 'user_name: FullTest' _bmad/core/config.yaml
|
||||
grep -q 'user_skill_level: advanced' _bmad/core/config.yaml
|
||||
"
|
||||
|
||||
# Test 8: Manifest tracking
|
||||
run_test "test-08-manifest-tracking" bash -c "
|
||||
node $PROJECT_ROOT/tools/bmad-npx-wrapper.js install -y --agents=dev
|
||||
verify_installation . 'dev' ''
|
||||
grep -q 'installMode: non-interactive' _bmad/_config/manifest.yaml
|
||||
grep -q 'selectedAgents:' _bmad/_config/manifest.yaml
|
||||
"
|
||||
|
||||
# Cleanup
|
||||
echo ""
|
||||
echo "🧹 Cleaning up test directory: $TEST_DIR"
|
||||
rm -rf "$TEST_DIR"
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test Summary"
|
||||
echo "================================================"
|
||||
echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"
|
||||
echo -e "${RED}Failed: $TESTS_FAILED${NC}"
|
||||
echo ""
|
||||
|
||||
if [ $TESTS_FAILED -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ All tests passed!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}✗ Some tests failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Loading…
Reference in New Issue