chore: add eslint config and apply code style fixes across codebase
This commit is contained in:
parent
3efcfd54d4
commit
d44aa4fed5
|
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
title: ""
|
title: ''
|
||||||
labels: ""
|
labels: ''
|
||||||
assignees: ""
|
assignees: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
name: Feature request
|
name: Feature request
|
||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
title: ""
|
title: ''
|
||||||
labels: ""
|
labels: ''
|
||||||
assignees: ""
|
assignees: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
**Did you discuss the idea first in Discord Server (#general-dev)**
|
**Did you discuss the idea first in Discord Server (#general-dev)**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
name: Discord Notification
|
name: Discord Notification
|
||||||
|
|
||||||
on: [pull_request, release, create, delete, issue_comment, pull_request_review, pull_request_review_comment]
|
on:
|
||||||
|
[
|
||||||
|
pull_request,
|
||||||
|
release,
|
||||||
|
create,
|
||||||
|
delete,
|
||||||
|
issue_comment,
|
||||||
|
pull_request_review,
|
||||||
|
pull_request_review_comment,
|
||||||
|
]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
notify:
|
notify:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
name: format-check
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: ["**"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
prettier:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: "npm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Prettier format check
|
||||||
|
run: npm run format:check
|
||||||
|
|
||||||
|
eslint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: "npm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: ESLint
|
||||||
|
run: npm run lint
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name: Release
|
name: Release
|
||||||
'on':
|
"on":
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
@ -22,7 +22,7 @@ permissions:
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: '!contains(github.event.head_commit.message, ''[skip ci]'')'
|
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -32,7 +32,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: "20"
|
||||||
cache: npm
|
cache: npm
|
||||||
registry-url: https://registry.npmjs.org
|
registry-url: https://registry.npmjs.org
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,12 @@
|
||||||
[
|
[
|
||||||
"@semantic-release/git",
|
"@semantic-release/git",
|
||||||
{
|
{
|
||||||
"assets": ["package.json", "package-lock.json", "tools/installer/package.json", "CHANGELOG.md"],
|
"assets": [
|
||||||
|
"package.json",
|
||||||
|
"package-lock.json",
|
||||||
|
"tools/installer/package.json",
|
||||||
|
"CHANGELOG.md"
|
||||||
|
],
|
||||||
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -40,5 +40,30 @@
|
||||||
"tileset",
|
"tileset",
|
||||||
"Trae",
|
"Trae",
|
||||||
"VNET"
|
"VNET"
|
||||||
]
|
],
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": ["package.json"],
|
||||||
|
"url": "https://json.schemastore.org/package.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fileMatch": [".vscode/settings.json"],
|
||||||
|
"url": "vscode://schemas/settings/folder"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"[yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"prettier.prettierPath": "node_modules/prettier",
|
||||||
|
"prettier.requireConfig": true,
|
||||||
|
"yaml.format.enable": false,
|
||||||
|
"eslint.useFlatConfig": true,
|
||||||
|
"eslint.validate": ["javascript", "yaml"],
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
},
|
||||||
|
"editor.rulers": [100]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ bundle:
|
||||||
description: Includes every core system agent.
|
description: Includes every core system agent.
|
||||||
agents:
|
agents:
|
||||||
- bmad-orchestrator
|
- bmad-orchestrator
|
||||||
- '*'
|
- "*"
|
||||||
workflows:
|
workflows:
|
||||||
- brownfield-fullstack.yaml
|
- brownfield-fullstack.yaml
|
||||||
- brownfield-service.yaml
|
- brownfield-service.yaml
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# architect
|
# architect
|
||||||
|
|
||||||
|
|
||||||
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
||||||
|
|
||||||
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# BMad Master
|
# BMad Master
|
||||||
|
|
||||||
|
|
||||||
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
||||||
|
|
||||||
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# BMad Web Orchestrator
|
# BMad Web Orchestrator
|
||||||
|
|
||||||
|
|
||||||
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
||||||
|
|
||||||
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
||||||
|
|
@ -132,7 +131,7 @@ workflow-guidance:
|
||||||
- Understand each workflow's purpose, options, and decision points
|
- Understand each workflow's purpose, options, and decision points
|
||||||
- Ask clarifying questions based on the workflow's structure
|
- Ask clarifying questions based on the workflow's structure
|
||||||
- Guide users through workflow selection when multiple options exist
|
- Guide users through workflow selection when multiple options exist
|
||||||
- When appropriate, suggest: "Would you like me to create a detailed workflow plan before starting?"
|
- When appropriate, suggest: 'Would you like me to create a detailed workflow plan before starting?'
|
||||||
- For workflows with divergent paths, help users choose the right path
|
- For workflows with divergent paths, help users choose the right path
|
||||||
- Adapt questions to the specific domain (e.g., game dev vs infrastructure vs web dev)
|
- Adapt questions to the specific domain (e.g., game dev vs infrastructure vs web dev)
|
||||||
- Only recommend workflows that actually exist in the current bundle
|
- Only recommend workflows that actually exist in the current bundle
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,9 @@ agent:
|
||||||
id: dev
|
id: dev
|
||||||
title: Full Stack Developer
|
title: Full Stack Developer
|
||||||
icon: 💻
|
icon: 💻
|
||||||
whenToUse: "Use for code implementation, debugging, refactoring, and development best practices"
|
whenToUse: 'Use for code implementation, debugging, refactoring, and development best practices'
|
||||||
customization:
|
customization:
|
||||||
|
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
role: Expert Senior Software Engineer & Implementation Specialist
|
role: Expert Senior Software Engineer & Implementation Specialist
|
||||||
style: Extremely concise, pragmatic, detail-oriented, solution-focused
|
style: Extremely concise, pragmatic, detail-oriented, solution-focused
|
||||||
|
|
@ -58,13 +57,13 @@ commands:
|
||||||
- explain: teach me what and why you did whatever you just did in detail so I can learn. Explain to me as if you were training a junior engineer.
|
- explain: teach me what and why you did whatever you just did in detail so I can learn. Explain to me as if you were training a junior engineer.
|
||||||
- exit: Say goodbye as the Developer, and then abandon inhabiting this persona
|
- exit: Say goodbye as the Developer, and then abandon inhabiting this persona
|
||||||
- develop-story:
|
- develop-story:
|
||||||
- order-of-execution: "Read (first or next) task→Implement Task and its subtasks→Write tests→Execute validations→Only if ALL pass, then update the task checkbox with [x]→Update story section File List to ensure it lists and new or modified or deleted source file→repeat order-of-execution until complete"
|
- order-of-execution: 'Read (first or next) task→Implement Task and its subtasks→Write tests→Execute validations→Only if ALL pass, then update the task checkbox with [x]→Update story section File List to ensure it lists and new or modified or deleted source file→repeat order-of-execution until complete'
|
||||||
- story-file-updates-ONLY:
|
- story-file-updates-ONLY:
|
||||||
- CRITICAL: ONLY UPDATE THE STORY FILE WITH UPDATES TO SECTIONS INDICATED BELOW. DO NOT MODIFY ANY OTHER SECTIONS.
|
- CRITICAL: ONLY UPDATE THE STORY FILE WITH UPDATES TO SECTIONS INDICATED BELOW. DO NOT MODIFY ANY OTHER SECTIONS.
|
||||||
- CRITICAL: You are ONLY authorized to edit these specific sections of story files - Tasks / Subtasks Checkboxes, Dev Agent Record section and all its subsections, Agent Model Used, Debug Log References, Completion Notes List, File List, Change Log, Status
|
- CRITICAL: You are ONLY authorized to edit these specific sections of story files - Tasks / Subtasks Checkboxes, Dev Agent Record section and all its subsections, Agent Model Used, Debug Log References, Completion Notes List, File List, Change Log, Status
|
||||||
- CRITICAL: DO NOT modify Status, Story, Acceptance Criteria, Dev Notes, Testing sections, or any other sections not listed above
|
- CRITICAL: DO NOT modify Status, Story, Acceptance Criteria, Dev Notes, Testing sections, or any other sections not listed above
|
||||||
- blocking: "HALT for: Unapproved deps needed, confirm with user | Ambiguous after story check | 3 failures attempting to implement or fix something repeatedly | Missing config | Failing regression"
|
- blocking: 'HALT for: Unapproved deps needed, confirm with user | Ambiguous after story check | 3 failures attempting to implement or fix something repeatedly | Missing config | Failing regression'
|
||||||
- ready-for-review: "Code matches requirements + All validations pass + Follows standards + File List complete"
|
- ready-for-review: 'Code matches requirements + All validations pass + Follows standards + File List complete'
|
||||||
- completion: "All Tasks and Subtasks marked [x] and have tests→Validations and full regression passes (DON'T BE LAZY, EXECUTE ALL TESTS and CONFIRM)→Ensure File List is Complete→run the task execute-checklist for the checklist story-dod-checklist→set story status: 'Ready for Review'→HALT"
|
- completion: "All Tasks and Subtasks marked [x] and have tests→Validations and full regression passes (DON'T BE LAZY, EXECUTE ALL TESTS and CONFIRM)→Ensure File List is Complete→run the task execute-checklist for the checklist story-dod-checklist→set story status: 'Ready for Review'→HALT"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
|
|
@ -403,33 +403,28 @@ Ask the user if they want to work through the checklist:
|
||||||
Now that you've completed the checklist, generate a comprehensive validation report that includes:
|
Now that you've completed the checklist, generate a comprehensive validation report that includes:
|
||||||
|
|
||||||
1. Executive Summary
|
1. Executive Summary
|
||||||
|
|
||||||
- Overall architecture readiness (High/Medium/Low)
|
- Overall architecture readiness (High/Medium/Low)
|
||||||
- Critical risks identified
|
- Critical risks identified
|
||||||
- Key strengths of the architecture
|
- Key strengths of the architecture
|
||||||
- Project type (Full-stack/Frontend/Backend) and sections evaluated
|
- Project type (Full-stack/Frontend/Backend) and sections evaluated
|
||||||
|
|
||||||
2. Section Analysis
|
2. Section Analysis
|
||||||
|
|
||||||
- Pass rate for each major section (percentage of items passed)
|
- Pass rate for each major section (percentage of items passed)
|
||||||
- Most concerning failures or gaps
|
- Most concerning failures or gaps
|
||||||
- Sections requiring immediate attention
|
- Sections requiring immediate attention
|
||||||
- Note any sections skipped due to project type
|
- Note any sections skipped due to project type
|
||||||
|
|
||||||
3. Risk Assessment
|
3. Risk Assessment
|
||||||
|
|
||||||
- Top 5 risks by severity
|
- Top 5 risks by severity
|
||||||
- Mitigation recommendations for each
|
- Mitigation recommendations for each
|
||||||
- Timeline impact of addressing issues
|
- Timeline impact of addressing issues
|
||||||
|
|
||||||
4. Recommendations
|
4. Recommendations
|
||||||
|
|
||||||
- Must-fix items before development
|
- Must-fix items before development
|
||||||
- Should-fix items for better quality
|
- Should-fix items for better quality
|
||||||
- Nice-to-have improvements
|
- Nice-to-have improvements
|
||||||
|
|
||||||
5. AI Implementation Readiness
|
5. AI Implementation Readiness
|
||||||
|
|
||||||
- Specific concerns for AI agent implementation
|
- Specific concerns for AI agent implementation
|
||||||
- Areas needing additional clarification
|
- Areas needing additional clarification
|
||||||
- Complexity hotspots to address
|
- Complexity hotspots to address
|
||||||
|
|
|
||||||
|
|
@ -304,7 +304,6 @@ Ask the user if they want to work through the checklist:
|
||||||
Create a comprehensive validation report that includes:
|
Create a comprehensive validation report that includes:
|
||||||
|
|
||||||
1. Executive Summary
|
1. Executive Summary
|
||||||
|
|
||||||
- Overall PRD completeness (percentage)
|
- Overall PRD completeness (percentage)
|
||||||
- MVP scope appropriateness (Too Large/Just Right/Too Small)
|
- MVP scope appropriateness (Too Large/Just Right/Too Small)
|
||||||
- Readiness for architecture phase (Ready/Nearly Ready/Not Ready)
|
- Readiness for architecture phase (Ready/Nearly Ready/Not Ready)
|
||||||
|
|
@ -312,26 +311,22 @@ Create a comprehensive validation report that includes:
|
||||||
|
|
||||||
2. Category Analysis Table
|
2. Category Analysis Table
|
||||||
Fill in the actual table with:
|
Fill in the actual table with:
|
||||||
|
|
||||||
- Status: PASS (90%+ complete), PARTIAL (60-89%), FAIL (<60%)
|
- Status: PASS (90%+ complete), PARTIAL (60-89%), FAIL (<60%)
|
||||||
- Critical Issues: Specific problems that block progress
|
- Critical Issues: Specific problems that block progress
|
||||||
|
|
||||||
3. Top Issues by Priority
|
3. Top Issues by Priority
|
||||||
|
|
||||||
- BLOCKERS: Must fix before architect can proceed
|
- BLOCKERS: Must fix before architect can proceed
|
||||||
- HIGH: Should fix for quality
|
- HIGH: Should fix for quality
|
||||||
- MEDIUM: Would improve clarity
|
- MEDIUM: Would improve clarity
|
||||||
- LOW: Nice to have
|
- LOW: Nice to have
|
||||||
|
|
||||||
4. MVP Scope Assessment
|
4. MVP Scope Assessment
|
||||||
|
|
||||||
- Features that might be cut for true MVP
|
- Features that might be cut for true MVP
|
||||||
- Missing features that are essential
|
- Missing features that are essential
|
||||||
- Complexity concerns
|
- Complexity concerns
|
||||||
- Timeline realism
|
- Timeline realism
|
||||||
|
|
||||||
5. Technical Readiness
|
5. Technical Readiness
|
||||||
|
|
||||||
- Clarity of technical constraints
|
- Clarity of technical constraints
|
||||||
- Identified technical risks
|
- Identified technical risks
|
||||||
- Areas needing architect investigation
|
- Areas needing architect investigation
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,10 @@ PROJECT TYPE DETECTION:
|
||||||
First, determine the project type by checking:
|
First, determine the project type by checking:
|
||||||
|
|
||||||
1. Is this a GREENFIELD project (new from scratch)?
|
1. Is this a GREENFIELD project (new from scratch)?
|
||||||
|
|
||||||
- Look for: New project initialization, no existing codebase references
|
- Look for: New project initialization, no existing codebase references
|
||||||
- Check for: prd.md, architecture.md, new project setup stories
|
- Check for: prd.md, architecture.md, new project setup stories
|
||||||
|
|
||||||
2. Is this a BROWNFIELD project (enhancing existing system)?
|
2. Is this a BROWNFIELD project (enhancing existing system)?
|
||||||
|
|
||||||
- Look for: References to existing codebase, enhancement/modification language
|
- Look for: References to existing codebase, enhancement/modification language
|
||||||
- Check for: brownfield-prd.md, brownfield-architecture.md, existing system analysis
|
- Check for: brownfield-prd.md, brownfield-architecture.md, existing system analysis
|
||||||
|
|
||||||
|
|
@ -347,7 +345,6 @@ Ask the user if they want to work through the checklist:
|
||||||
Generate a comprehensive validation report that adapts to project type:
|
Generate a comprehensive validation report that adapts to project type:
|
||||||
|
|
||||||
1. Executive Summary
|
1. Executive Summary
|
||||||
|
|
||||||
- Project type: [Greenfield/Brownfield] with [UI/No UI]
|
- Project type: [Greenfield/Brownfield] with [UI/No UI]
|
||||||
- Overall readiness (percentage)
|
- Overall readiness (percentage)
|
||||||
- Go/No-Go recommendation
|
- Go/No-Go recommendation
|
||||||
|
|
@ -357,42 +354,36 @@ Generate a comprehensive validation report that adapts to project type:
|
||||||
2. Project-Specific Analysis
|
2. Project-Specific Analysis
|
||||||
|
|
||||||
FOR GREENFIELD:
|
FOR GREENFIELD:
|
||||||
|
|
||||||
- Setup completeness
|
- Setup completeness
|
||||||
- Dependency sequencing
|
- Dependency sequencing
|
||||||
- MVP scope appropriateness
|
- MVP scope appropriateness
|
||||||
- Development timeline feasibility
|
- Development timeline feasibility
|
||||||
|
|
||||||
FOR BROWNFIELD:
|
FOR BROWNFIELD:
|
||||||
|
|
||||||
- Integration risk level (High/Medium/Low)
|
- Integration risk level (High/Medium/Low)
|
||||||
- Existing system impact assessment
|
- Existing system impact assessment
|
||||||
- Rollback readiness
|
- Rollback readiness
|
||||||
- User disruption potential
|
- User disruption potential
|
||||||
|
|
||||||
3. Risk Assessment
|
3. Risk Assessment
|
||||||
|
|
||||||
- Top 5 risks by severity
|
- Top 5 risks by severity
|
||||||
- Mitigation recommendations
|
- Mitigation recommendations
|
||||||
- Timeline impact of addressing issues
|
- Timeline impact of addressing issues
|
||||||
- [BROWNFIELD] Specific integration risks
|
- [BROWNFIELD] Specific integration risks
|
||||||
|
|
||||||
4. MVP Completeness
|
4. MVP Completeness
|
||||||
|
|
||||||
- Core features coverage
|
- Core features coverage
|
||||||
- Missing essential functionality
|
- Missing essential functionality
|
||||||
- Scope creep identified
|
- Scope creep identified
|
||||||
- True MVP vs over-engineering
|
- True MVP vs over-engineering
|
||||||
|
|
||||||
5. Implementation Readiness
|
5. Implementation Readiness
|
||||||
|
|
||||||
- Developer clarity score (1-10)
|
- Developer clarity score (1-10)
|
||||||
- Ambiguous requirements count
|
- Ambiguous requirements count
|
||||||
- Missing technical details
|
- Missing technical details
|
||||||
- [BROWNFIELD] Integration point clarity
|
- [BROWNFIELD] Integration point clarity
|
||||||
|
|
||||||
6. Recommendations
|
6. Recommendations
|
||||||
|
|
||||||
- Must-fix before development
|
- Must-fix before development
|
||||||
- Should-fix for quality
|
- Should-fix for quality
|
||||||
- Consider for improvement
|
- Consider for improvement
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,12 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
1. **Requirements Met:**
|
1. **Requirements Met:**
|
||||||
|
|
||||||
[[LLM: Be specific - list each requirement and whether it's complete]]
|
[[LLM: Be specific - list each requirement and whether it's complete]]
|
||||||
|
|
||||||
- [ ] All functional requirements specified in the story are implemented.
|
- [ ] All functional requirements specified in the story are implemented.
|
||||||
- [ ] All acceptance criteria defined in the story are met.
|
- [ ] All acceptance criteria defined in the story are met.
|
||||||
|
|
||||||
2. **Coding Standards & Project Structure:**
|
2. **Coding Standards & Project Structure:**
|
||||||
|
|
||||||
[[LLM: Code quality matters for maintainability. Check each item carefully]]
|
[[LLM: Code quality matters for maintainability. Check each item carefully]]
|
||||||
|
|
||||||
- [ ] All new/modified code strictly adheres to `Operational Guidelines`.
|
- [ ] All new/modified code strictly adheres to `Operational Guidelines`.
|
||||||
- [ ] All new/modified code aligns with `Project Structure` (file locations, naming, etc.).
|
- [ ] All new/modified code aligns with `Project Structure` (file locations, naming, etc.).
|
||||||
- [ ] Adherence to `Tech Stack` for technologies/versions used (if story introduces or modifies tech usage).
|
- [ ] Adherence to `Tech Stack` for technologies/versions used (if story introduces or modifies tech usage).
|
||||||
|
|
@ -44,7 +42,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
3. **Testing:**
|
3. **Testing:**
|
||||||
|
|
||||||
[[LLM: Testing proves your code works. Be honest about test coverage]]
|
[[LLM: Testing proves your code works. Be honest about test coverage]]
|
||||||
|
|
||||||
- [ ] All required unit tests as per the story and `Operational Guidelines` Testing Strategy are implemented.
|
- [ ] All required unit tests as per the story and `Operational Guidelines` Testing Strategy are implemented.
|
||||||
- [ ] All required integration tests (if applicable) as per the story and `Operational Guidelines` Testing Strategy are implemented.
|
- [ ] All required integration tests (if applicable) as per the story and `Operational Guidelines` Testing Strategy are implemented.
|
||||||
- [ ] All tests (unit, integration, E2E if applicable) pass successfully.
|
- [ ] All tests (unit, integration, E2E if applicable) pass successfully.
|
||||||
|
|
@ -53,14 +50,12 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
4. **Functionality & Verification:**
|
4. **Functionality & Verification:**
|
||||||
|
|
||||||
[[LLM: Did you actually run and test your code? Be specific about what you tested]]
|
[[LLM: Did you actually run and test your code? Be specific about what you tested]]
|
||||||
|
|
||||||
- [ ] Functionality has been manually verified by the developer (e.g., running the app locally, checking UI, testing API endpoints).
|
- [ ] Functionality has been manually verified by the developer (e.g., running the app locally, checking UI, testing API endpoints).
|
||||||
- [ ] Edge cases and potential error conditions considered and handled gracefully.
|
- [ ] Edge cases and potential error conditions considered and handled gracefully.
|
||||||
|
|
||||||
5. **Story Administration:**
|
5. **Story Administration:**
|
||||||
|
|
||||||
[[LLM: Documentation helps the next developer. What should they know?]]
|
[[LLM: Documentation helps the next developer. What should they know?]]
|
||||||
|
|
||||||
- [ ] All tasks within the story file are marked as complete.
|
- [ ] All tasks within the story file are marked as complete.
|
||||||
- [ ] Any clarifications or decisions made during development are documented in the story file or linked appropriately.
|
- [ ] Any clarifications or decisions made during development are documented in the story file or linked appropriately.
|
||||||
- [ ] The story wrap up section has been completed with notes of changes or information relevant to the next story or overall project, the agent model that was primarily used during development, and the changelog of any changes is properly updated.
|
- [ ] The story wrap up section has been completed with notes of changes or information relevant to the next story or overall project, the agent model that was primarily used during development, and the changelog of any changes is properly updated.
|
||||||
|
|
@ -68,7 +63,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
6. **Dependencies, Build & Configuration:**
|
6. **Dependencies, Build & Configuration:**
|
||||||
|
|
||||||
[[LLM: Build issues block everyone. Ensure everything compiles and runs cleanly]]
|
[[LLM: Build issues block everyone. Ensure everything compiles and runs cleanly]]
|
||||||
|
|
||||||
- [ ] Project builds successfully without errors.
|
- [ ] Project builds successfully without errors.
|
||||||
- [ ] Project linting passes
|
- [ ] Project linting passes
|
||||||
- [ ] Any new dependencies added were either pre-approved in the story requirements OR explicitly approved by the user during development (approval documented in story file).
|
- [ ] Any new dependencies added were either pre-approved in the story requirements OR explicitly approved by the user during development (approval documented in story file).
|
||||||
|
|
@ -79,7 +73,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
7. **Documentation (If Applicable):**
|
7. **Documentation (If Applicable):**
|
||||||
|
|
||||||
[[LLM: Good documentation prevents future confusion. What needs explaining?]]
|
[[LLM: Good documentation prevents future confusion. What needs explaining?]]
|
||||||
|
|
||||||
- [ ] Relevant inline code documentation (e.g., JSDoc, TSDoc, Python docstrings) for new public APIs or complex logic is complete.
|
- [ ] Relevant inline code documentation (e.g., JSDoc, TSDoc, Python docstrings) for new public APIs or complex logic is complete.
|
||||||
- [ ] User-facing documentation updated, if changes impact users.
|
- [ ] User-facing documentation updated, if changes impact users.
|
||||||
- [ ] Technical documentation (e.g., READMEs, system diagrams) updated if significant architectural changes were made.
|
- [ ] Technical documentation (e.g., READMEs, system diagrams) updated if significant architectural changes were made.
|
||||||
|
|
|
||||||
|
|
@ -117,19 +117,16 @@ Note: We don't need every file listed - just the important ones.]]
|
||||||
Generate a concise validation report:
|
Generate a concise validation report:
|
||||||
|
|
||||||
1. Quick Summary
|
1. Quick Summary
|
||||||
|
|
||||||
- Story readiness: READY / NEEDS REVISION / BLOCKED
|
- Story readiness: READY / NEEDS REVISION / BLOCKED
|
||||||
- Clarity score (1-10)
|
- Clarity score (1-10)
|
||||||
- Major gaps identified
|
- Major gaps identified
|
||||||
|
|
||||||
2. Fill in the validation table with:
|
2. Fill in the validation table with:
|
||||||
|
|
||||||
- PASS: Requirements clearly met
|
- PASS: Requirements clearly met
|
||||||
- PARTIAL: Some gaps but workable
|
- PARTIAL: Some gaps but workable
|
||||||
- FAIL: Critical information missing
|
- FAIL: Critical information missing
|
||||||
|
|
||||||
3. Specific Issues (if any)
|
3. Specific Issues (if any)
|
||||||
|
|
||||||
- List concrete problems to fix
|
- List concrete problems to fix
|
||||||
- Suggest specific improvements
|
- Suggest specific improvements
|
||||||
- Identify any blocking dependencies
|
- Identify any blocking dependencies
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
@ -651,8 +651,11 @@ Templates with Level 2 headings (`##`) can be automatically sharded:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
## Goals and Background Context
|
## Goals and Background Context
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
## User Interface Design Goals
|
## User Interface Design Goals
|
||||||
|
|
||||||
## Success Metrics
|
## Success Metrics
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,19 @@
|
||||||
## Core Reflective Methods
|
## Core Reflective Methods
|
||||||
|
|
||||||
**Expand or Contract for Audience**
|
**Expand or Contract for Audience**
|
||||||
|
|
||||||
- Ask whether to 'expand' (add detail, elaborate) or 'contract' (simplify, clarify)
|
- Ask whether to 'expand' (add detail, elaborate) or 'contract' (simplify, clarify)
|
||||||
- Identify specific target audience if relevant
|
- Identify specific target audience if relevant
|
||||||
- Tailor content complexity and depth accordingly
|
- Tailor content complexity and depth accordingly
|
||||||
|
|
||||||
**Explain Reasoning (CoT Step-by-Step)**
|
**Explain Reasoning (CoT Step-by-Step)**
|
||||||
|
|
||||||
- Walk through the step-by-step thinking process
|
- Walk through the step-by-step thinking process
|
||||||
- Reveal underlying assumptions and decision points
|
- Reveal underlying assumptions and decision points
|
||||||
- Show how conclusions were reached from current role's perspective
|
- Show how conclusions were reached from current role's perspective
|
||||||
|
|
||||||
**Critique and Refine**
|
**Critique and Refine**
|
||||||
|
|
||||||
- Review output for flaws, inconsistencies, or improvement areas
|
- Review output for flaws, inconsistencies, or improvement areas
|
||||||
- Identify specific weaknesses from role's expertise
|
- Identify specific weaknesses from role's expertise
|
||||||
- Suggest refined version reflecting domain knowledge
|
- Suggest refined version reflecting domain knowledge
|
||||||
|
|
@ -20,12 +23,14 @@
|
||||||
## Structural Analysis Methods
|
## Structural Analysis Methods
|
||||||
|
|
||||||
**Analyze Logical Flow and Dependencies**
|
**Analyze Logical Flow and Dependencies**
|
||||||
|
|
||||||
- Examine content structure for logical progression
|
- Examine content structure for logical progression
|
||||||
- Check internal consistency and coherence
|
- Check internal consistency and coherence
|
||||||
- Identify and validate dependencies between elements
|
- Identify and validate dependencies between elements
|
||||||
- Confirm effective ordering and sequencing
|
- Confirm effective ordering and sequencing
|
||||||
|
|
||||||
**Assess Alignment with Overall Goals**
|
**Assess Alignment with Overall Goals**
|
||||||
|
|
||||||
- Evaluate content contribution to stated objectives
|
- Evaluate content contribution to stated objectives
|
||||||
- Identify any misalignments or gaps
|
- Identify any misalignments or gaps
|
||||||
- Interpret alignment from specific role's perspective
|
- Interpret alignment from specific role's perspective
|
||||||
|
|
@ -34,12 +39,14 @@
|
||||||
## Risk and Challenge Methods
|
## Risk and Challenge Methods
|
||||||
|
|
||||||
**Identify Potential Risks and Unforeseen Issues**
|
**Identify Potential Risks and Unforeseen Issues**
|
||||||
|
|
||||||
- Brainstorm potential risks from role's expertise
|
- Brainstorm potential risks from role's expertise
|
||||||
- Identify overlooked edge cases or scenarios
|
- Identify overlooked edge cases or scenarios
|
||||||
- Anticipate unintended consequences
|
- Anticipate unintended consequences
|
||||||
- Highlight implementation challenges
|
- Highlight implementation challenges
|
||||||
|
|
||||||
**Challenge from Critical Perspective**
|
**Challenge from Critical Perspective**
|
||||||
|
|
||||||
- Adopt critical stance on current content
|
- Adopt critical stance on current content
|
||||||
- Play devil's advocate from specified viewpoint
|
- Play devil's advocate from specified viewpoint
|
||||||
- Argue against proposal highlighting weaknesses
|
- Argue against proposal highlighting weaknesses
|
||||||
|
|
@ -48,12 +55,14 @@
|
||||||
## Creative Exploration Methods
|
## Creative Exploration Methods
|
||||||
|
|
||||||
**Tree of Thoughts Deep Dive**
|
**Tree of Thoughts Deep Dive**
|
||||||
|
|
||||||
- Break problem into discrete "thoughts" or intermediate steps
|
- Break problem into discrete "thoughts" or intermediate steps
|
||||||
- Explore multiple reasoning paths simultaneously
|
- Explore multiple reasoning paths simultaneously
|
||||||
- Use self-evaluation to classify each path as "sure", "likely", or "impossible"
|
- Use self-evaluation to classify each path as "sure", "likely", or "impossible"
|
||||||
- Apply search algorithms (BFS/DFS) to find optimal solution paths
|
- Apply search algorithms (BFS/DFS) to find optimal solution paths
|
||||||
|
|
||||||
**Hindsight is 20/20: The 'If Only...' Reflection**
|
**Hindsight is 20/20: The 'If Only...' Reflection**
|
||||||
|
|
||||||
- Imagine retrospective scenario based on current content
|
- Imagine retrospective scenario based on current content
|
||||||
- Identify the one "if only we had known/done X..." insight
|
- Identify the one "if only we had known/done X..." insight
|
||||||
- Describe imagined consequences humorously or dramatically
|
- Describe imagined consequences humorously or dramatically
|
||||||
|
|
@ -62,6 +71,7 @@
|
||||||
## Multi-Persona Collaboration Methods
|
## Multi-Persona Collaboration Methods
|
||||||
|
|
||||||
**Agile Team Perspective Shift**
|
**Agile Team Perspective Shift**
|
||||||
|
|
||||||
- Rotate through different Scrum team member viewpoints
|
- Rotate through different Scrum team member viewpoints
|
||||||
- Product Owner: Focus on user value and business impact
|
- Product Owner: Focus on user value and business impact
|
||||||
- Scrum Master: Examine process flow and team dynamics
|
- Scrum Master: Examine process flow and team dynamics
|
||||||
|
|
@ -69,12 +79,14 @@
|
||||||
- QA: Identify testing scenarios and quality concerns
|
- QA: Identify testing scenarios and quality concerns
|
||||||
|
|
||||||
**Stakeholder Round Table**
|
**Stakeholder Round Table**
|
||||||
|
|
||||||
- Convene virtual meeting with multiple personas
|
- Convene virtual meeting with multiple personas
|
||||||
- Each persona contributes unique perspective on content
|
- Each persona contributes unique perspective on content
|
||||||
- Identify conflicts and synergies between viewpoints
|
- Identify conflicts and synergies between viewpoints
|
||||||
- Synthesize insights into actionable recommendations
|
- Synthesize insights into actionable recommendations
|
||||||
|
|
||||||
**Meta-Prompting Analysis**
|
**Meta-Prompting Analysis**
|
||||||
|
|
||||||
- Step back to analyze the structure and logic of current approach
|
- Step back to analyze the structure and logic of current approach
|
||||||
- Question the format and methodology being used
|
- Question the format and methodology being used
|
||||||
- Suggest alternative frameworks or mental models
|
- Suggest alternative frameworks or mental models
|
||||||
|
|
@ -83,24 +95,28 @@
|
||||||
## Advanced 2025 Techniques
|
## Advanced 2025 Techniques
|
||||||
|
|
||||||
**Self-Consistency Validation**
|
**Self-Consistency Validation**
|
||||||
|
|
||||||
- Generate multiple reasoning paths for same problem
|
- Generate multiple reasoning paths for same problem
|
||||||
- Compare consistency across different approaches
|
- Compare consistency across different approaches
|
||||||
- Identify most reliable and robust solution
|
- Identify most reliable and robust solution
|
||||||
- Highlight areas where approaches diverge and why
|
- Highlight areas where approaches diverge and why
|
||||||
|
|
||||||
**ReWOO (Reasoning Without Observation)**
|
**ReWOO (Reasoning Without Observation)**
|
||||||
|
|
||||||
- Separate parametric reasoning from tool-based actions
|
- Separate parametric reasoning from tool-based actions
|
||||||
- Create reasoning plan without external dependencies
|
- Create reasoning plan without external dependencies
|
||||||
- Identify what can be solved through pure reasoning
|
- Identify what can be solved through pure reasoning
|
||||||
- Optimize for efficiency and reduced token usage
|
- Optimize for efficiency and reduced token usage
|
||||||
|
|
||||||
**Persona-Pattern Hybrid**
|
**Persona-Pattern Hybrid**
|
||||||
|
|
||||||
- Combine specific role expertise with elicitation pattern
|
- Combine specific role expertise with elicitation pattern
|
||||||
- Architect + Risk Analysis: Deep technical risk assessment
|
- Architect + Risk Analysis: Deep technical risk assessment
|
||||||
- UX Expert + User Journey: End-to-end experience critique
|
- UX Expert + User Journey: End-to-end experience critique
|
||||||
- PM + Stakeholder Analysis: Multi-perspective impact review
|
- PM + Stakeholder Analysis: Multi-perspective impact review
|
||||||
|
|
||||||
**Emergent Collaboration Discovery**
|
**Emergent Collaboration Discovery**
|
||||||
|
|
||||||
- Allow multiple perspectives to naturally emerge
|
- Allow multiple perspectives to naturally emerge
|
||||||
- Identify unexpected insights from persona interactions
|
- Identify unexpected insights from persona interactions
|
||||||
- Explore novel combinations of viewpoints
|
- Explore novel combinations of viewpoints
|
||||||
|
|
@ -109,18 +125,21 @@
|
||||||
## Game-Based Elicitation Methods
|
## Game-Based Elicitation Methods
|
||||||
|
|
||||||
**Red Team vs Blue Team**
|
**Red Team vs Blue Team**
|
||||||
|
|
||||||
- Red Team: Attack the proposal, find vulnerabilities
|
- Red Team: Attack the proposal, find vulnerabilities
|
||||||
- Blue Team: Defend and strengthen the approach
|
- Blue Team: Defend and strengthen the approach
|
||||||
- Competitive analysis reveals blind spots
|
- Competitive analysis reveals blind spots
|
||||||
- Results in more robust, battle-tested solutions
|
- Results in more robust, battle-tested solutions
|
||||||
|
|
||||||
**Innovation Tournament**
|
**Innovation Tournament**
|
||||||
|
|
||||||
- Pit multiple alternative approaches against each other
|
- Pit multiple alternative approaches against each other
|
||||||
- Score each approach across different criteria
|
- Score each approach across different criteria
|
||||||
- Crowd-source evaluation from different personas
|
- Crowd-source evaluation from different personas
|
||||||
- Identify winning combination of features
|
- Identify winning combination of features
|
||||||
|
|
||||||
**Escape Room Challenge**
|
**Escape Room Challenge**
|
||||||
|
|
||||||
- Present content as constraints to work within
|
- Present content as constraints to work within
|
||||||
- Find creative solutions within tight limitations
|
- Find creative solutions within tight limitations
|
||||||
- Identify minimum viable approach
|
- Identify minimum viable approach
|
||||||
|
|
@ -129,6 +148,7 @@
|
||||||
## Process Control
|
## Process Control
|
||||||
|
|
||||||
**Proceed / No Further Actions**
|
**Proceed / No Further Actions**
|
||||||
|
|
||||||
- Acknowledge choice to finalize current work
|
- Acknowledge choice to finalize current work
|
||||||
- Accept output as-is or move to next step
|
- Accept output as-is or move to next step
|
||||||
- Prepare to continue without additional elicitation
|
- Prepare to continue without additional elicitation
|
||||||
|
|
|
||||||
|
|
@ -139,16 +139,19 @@ Critical: This is where you'll need to be interactive with the user if informati
|
||||||
|
|
||||||
Create Dev Technical Guidance section with available information:
|
Create Dev Technical Guidance section with available information:
|
||||||
|
|
||||||
```markdown
|
````markdown
|
||||||
## Dev Technical Guidance
|
## Dev Technical Guidance
|
||||||
|
|
||||||
### Existing System Context
|
### Existing System Context
|
||||||
|
|
||||||
[Extract from available documentation]
|
[Extract from available documentation]
|
||||||
|
|
||||||
### Integration Approach
|
### Integration Approach
|
||||||
|
|
||||||
[Based on patterns found or ask user]
|
[Based on patterns found or ask user]
|
||||||
|
|
||||||
### Technical Constraints
|
### Technical Constraints
|
||||||
|
|
||||||
[From documentation or user input]
|
[From documentation or user input]
|
||||||
|
|
||||||
### Missing Information
|
### Missing Information
|
||||||
|
|
@ -191,6 +194,7 @@ Example task structure for brownfield:
|
||||||
- [ ] Integration test for {{integration point}}
|
- [ ] Integration test for {{integration point}}
|
||||||
- [ ] Update existing tests if needed
|
- [ ] Update existing tests if needed
|
||||||
```
|
```
|
||||||
|
````
|
||||||
|
|
||||||
### 5. Risk Assessment and Mitigation
|
### 5. Risk Assessment and Mitigation
|
||||||
|
|
||||||
|
|
@ -202,14 +206,17 @@ Add section for brownfield-specific risks:
|
||||||
## Risk Assessment
|
## Risk Assessment
|
||||||
|
|
||||||
### Implementation Risks
|
### Implementation Risks
|
||||||
|
|
||||||
- **Primary Risk**: {{main risk to existing system}}
|
- **Primary Risk**: {{main risk to existing system}}
|
||||||
- **Mitigation**: {{how to address}}
|
- **Mitigation**: {{how to address}}
|
||||||
- **Verification**: {{how to confirm safety}}
|
- **Verification**: {{how to confirm safety}}
|
||||||
|
|
||||||
### Rollback Plan
|
### Rollback Plan
|
||||||
|
|
||||||
- {{Simple steps to undo changes if needed}}
|
- {{Simple steps to undo changes if needed}}
|
||||||
|
|
||||||
### Safety Checks
|
### Safety Checks
|
||||||
|
|
||||||
- [ ] Existing {{feature}} tested before changes
|
- [ ] Existing {{feature}} tested before changes
|
||||||
- [ ] Changes can be feature-flagged or isolated
|
- [ ] Changes can be feature-flagged or isolated
|
||||||
- [ ] Rollback procedure documented
|
- [ ] Rollback procedure documented
|
||||||
|
|
@ -252,6 +259,7 @@ Include header noting documentation context:
|
||||||
<!-- Context: Brownfield enhancement to {{existing system}} -->
|
<!-- Context: Brownfield enhancement to {{existing system}} -->
|
||||||
|
|
||||||
## Status: Draft
|
## Status: Draft
|
||||||
|
|
||||||
[Rest of story content...]
|
[Rest of story content...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,63 +21,54 @@ CRITICAL: First, help the user select the most appropriate research focus based
|
||||||
Present these numbered options to the user:
|
Present these numbered options to the user:
|
||||||
|
|
||||||
1. **Product Validation Research**
|
1. **Product Validation Research**
|
||||||
|
|
||||||
- Validate product hypotheses and market fit
|
- Validate product hypotheses and market fit
|
||||||
- Test assumptions about user needs and solutions
|
- Test assumptions about user needs and solutions
|
||||||
- Assess technical and business feasibility
|
- Assess technical and business feasibility
|
||||||
- Identify risks and mitigation strategies
|
- Identify risks and mitigation strategies
|
||||||
|
|
||||||
2. **Market Opportunity Research**
|
2. **Market Opportunity Research**
|
||||||
|
|
||||||
- Analyze market size and growth potential
|
- Analyze market size and growth potential
|
||||||
- Identify market segments and dynamics
|
- Identify market segments and dynamics
|
||||||
- Assess market entry strategies
|
- Assess market entry strategies
|
||||||
- Evaluate timing and market readiness
|
- Evaluate timing and market readiness
|
||||||
|
|
||||||
3. **User & Customer Research**
|
3. **User & Customer Research**
|
||||||
|
|
||||||
- Deep dive into user personas and behaviors
|
- Deep dive into user personas and behaviors
|
||||||
- Understand jobs-to-be-done and pain points
|
- Understand jobs-to-be-done and pain points
|
||||||
- Map customer journeys and touchpoints
|
- Map customer journeys and touchpoints
|
||||||
- Analyze willingness to pay and value perception
|
- Analyze willingness to pay and value perception
|
||||||
|
|
||||||
4. **Competitive Intelligence Research**
|
4. **Competitive Intelligence Research**
|
||||||
|
|
||||||
- Detailed competitor analysis and positioning
|
- Detailed competitor analysis and positioning
|
||||||
- Feature and capability comparisons
|
- Feature and capability comparisons
|
||||||
- Business model and strategy analysis
|
- Business model and strategy analysis
|
||||||
- Identify competitive advantages and gaps
|
- Identify competitive advantages and gaps
|
||||||
|
|
||||||
5. **Technology & Innovation Research**
|
5. **Technology & Innovation Research**
|
||||||
|
|
||||||
- Assess technology trends and possibilities
|
- Assess technology trends and possibilities
|
||||||
- Evaluate technical approaches and architectures
|
- Evaluate technical approaches and architectures
|
||||||
- Identify emerging technologies and disruptions
|
- Identify emerging technologies and disruptions
|
||||||
- Analyze build vs. buy vs. partner options
|
- Analyze build vs. buy vs. partner options
|
||||||
|
|
||||||
6. **Industry & Ecosystem Research**
|
6. **Industry & Ecosystem Research**
|
||||||
|
|
||||||
- Map industry value chains and dynamics
|
- Map industry value chains and dynamics
|
||||||
- Identify key players and relationships
|
- Identify key players and relationships
|
||||||
- Analyze regulatory and compliance factors
|
- Analyze regulatory and compliance factors
|
||||||
- Understand partnership opportunities
|
- Understand partnership opportunities
|
||||||
|
|
||||||
7. **Strategic Options Research**
|
7. **Strategic Options Research**
|
||||||
|
|
||||||
- Evaluate different strategic directions
|
- Evaluate different strategic directions
|
||||||
- Assess business model alternatives
|
- Assess business model alternatives
|
||||||
- Analyze go-to-market strategies
|
- Analyze go-to-market strategies
|
||||||
- Consider expansion and scaling paths
|
- Consider expansion and scaling paths
|
||||||
|
|
||||||
8. **Risk & Feasibility Research**
|
8. **Risk & Feasibility Research**
|
||||||
|
|
||||||
- Identify and assess various risk factors
|
- Identify and assess various risk factors
|
||||||
- Evaluate implementation challenges
|
- Evaluate implementation challenges
|
||||||
- Analyze resource requirements
|
- Analyze resource requirements
|
||||||
- Consider regulatory and legal implications
|
- Consider regulatory and legal implications
|
||||||
|
|
||||||
9. **Custom Research Focus**
|
9. **Custom Research Focus**
|
||||||
|
|
||||||
- User-defined research objectives
|
- User-defined research objectives
|
||||||
- Specialized domain investigation
|
- Specialized domain investigation
|
||||||
- Cross-functional research needs
|
- Cross-functional research needs
|
||||||
|
|
@ -246,13 +237,11 @@ CRITICAL: collaborate with the user to develop specific, actionable research que
|
||||||
### 5. Review and Refinement
|
### 5. Review and Refinement
|
||||||
|
|
||||||
1. **Present Complete Prompt**
|
1. **Present Complete Prompt**
|
||||||
|
|
||||||
- Show the full research prompt
|
- Show the full research prompt
|
||||||
- Explain key elements and rationale
|
- Explain key elements and rationale
|
||||||
- Highlight any assumptions made
|
- Highlight any assumptions made
|
||||||
|
|
||||||
2. **Gather Feedback**
|
2. **Gather Feedback**
|
||||||
|
|
||||||
- Are the objectives clear and correct?
|
- Are the objectives clear and correct?
|
||||||
- Do the questions address all concerns?
|
- Do the questions address all concerns?
|
||||||
- Is the scope appropriate?
|
- Is the scope appropriate?
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ This document captures the CURRENT STATE of the [Project Name] codebase, includi
|
||||||
### Change Log
|
### Change Log
|
||||||
|
|
||||||
| Date | Version | Description | Author |
|
| Date | Version | Description | Author |
|
||||||
|------|---------|-------------|--------|
|
| ------ | ------- | --------------------------- | --------- |
|
||||||
| [Date] | 1.0 | Initial brownfield analysis | [Analyst] |
|
| [Date] | 1.0 | Initial brownfield analysis | [Analyst] |
|
||||||
|
|
||||||
## Quick Reference - Key Files and Entry Points
|
## Quick Reference - Key Files and Entry Points
|
||||||
|
|
@ -137,7 +137,7 @@ This document captures the CURRENT STATE of the [Project Name] codebase, includi
|
||||||
### Actual Tech Stack (from package.json/requirements.txt)
|
### Actual Tech Stack (from package.json/requirements.txt)
|
||||||
|
|
||||||
| Category | Technology | Version | Notes |
|
| Category | Technology | Version | Notes |
|
||||||
|----------|------------|---------|--------|
|
| --------- | ---------- | ------- | -------------------------- |
|
||||||
| Runtime | Node.js | 16.x | [Any constraints] |
|
| Runtime | Node.js | 16.x | [Any constraints] |
|
||||||
| Framework | Express | 4.18.2 | [Custom middleware?] |
|
| Framework | Express | 4.18.2 | [Custom middleware?] |
|
||||||
| Database | PostgreSQL | 13 | [Connection pooling setup] |
|
| Database | PostgreSQL | 13 | [Connection pooling setup] |
|
||||||
|
|
@ -179,6 +179,7 @@ project-root/
|
||||||
### Data Models
|
### Data Models
|
||||||
|
|
||||||
Instead of duplicating, reference actual model files:
|
Instead of duplicating, reference actual model files:
|
||||||
|
|
||||||
- **User Model**: See `src/models/User.js`
|
- **User Model**: See `src/models/User.js`
|
||||||
- **Order Model**: See `src/models/Order.js`
|
- **Order Model**: See `src/models/Order.js`
|
||||||
- **Related Types**: TypeScript definitions in `src/types/`
|
- **Related Types**: TypeScript definitions in `src/types/`
|
||||||
|
|
@ -209,7 +210,7 @@ Instead of duplicating, reference actual model files:
|
||||||
### External Services
|
### External Services
|
||||||
|
|
||||||
| Service | Purpose | Integration Type | Key Files |
|
| Service | Purpose | Integration Type | Key Files |
|
||||||
|---------|---------|------------------|-----------|
|
| -------- | -------- | ---------------- | ------------------------------ |
|
||||||
| Stripe | Payments | REST API | `src/integrations/stripe/` |
|
| Stripe | Payments | REST API | `src/integrations/stripe/` |
|
||||||
| SendGrid | Emails | SDK | `src/services/emailService.js` |
|
| SendGrid | Emails | SDK | `src/services/emailService.js` |
|
||||||
|
|
||||||
|
|
@ -256,6 +257,7 @@ npm run test:integration # Runs integration tests (requires local DB)
|
||||||
### Files That Will Need Modification
|
### Files That Will Need Modification
|
||||||
|
|
||||||
Based on the enhancement requirements, these files will be affected:
|
Based on the enhancement requirements, these files will be affected:
|
||||||
|
|
||||||
- `src/services/userService.js` - Add new user fields
|
- `src/services/userService.js` - Add new user fields
|
||||||
- `src/models/User.js` - Update schema
|
- `src/models/User.js` - Update schema
|
||||||
- `src/routes/userRoutes.js` - New endpoints
|
- `src/routes/userRoutes.js` - New endpoints
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
docOutputLocation: docs/brainstorming-session-results.md
|
docOutputLocation: docs/brainstorming-session-results.md
|
||||||
template: "{root}/templates/brainstorming-output-tmpl.yaml"
|
template: '{root}/templates/brainstorming-output-tmpl.yaml'
|
||||||
---
|
---
|
||||||
|
|
||||||
# Facilitate Brainstorming Session Task
|
# Facilitate Brainstorming Session Task
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,12 @@ You are now operating as a Documentation Indexer. Your goal is to ensure all doc
|
||||||
### Required Steps
|
### Required Steps
|
||||||
|
|
||||||
1. First, locate and scan:
|
1. First, locate and scan:
|
||||||
|
|
||||||
- The `docs/` directory and all subdirectories
|
- The `docs/` directory and all subdirectories
|
||||||
- The existing `docs/index.md` file (create if absent)
|
- The existing `docs/index.md` file (create if absent)
|
||||||
- All markdown (`.md`) and text (`.txt`) files in the documentation structure
|
- All markdown (`.md`) and text (`.txt`) files in the documentation structure
|
||||||
- Note the folder structure for hierarchical organization
|
- Note the folder structure for hierarchical organization
|
||||||
|
|
||||||
2. For the existing `docs/index.md`:
|
2. For the existing `docs/index.md`:
|
||||||
|
|
||||||
- Parse current entries
|
- Parse current entries
|
||||||
- Note existing file references and descriptions
|
- Note existing file references and descriptions
|
||||||
- Identify any broken links or missing files
|
- Identify any broken links or missing files
|
||||||
|
|
@ -26,7 +24,6 @@ You are now operating as a Documentation Indexer. Your goal is to ensure all doc
|
||||||
- Preserve existing folder sections
|
- Preserve existing folder sections
|
||||||
|
|
||||||
3. For each documentation file found:
|
3. For each documentation file found:
|
||||||
|
|
||||||
- Extract the title (from first heading or filename)
|
- Extract the title (from first heading or filename)
|
||||||
- Generate a brief description by analyzing the content
|
- Generate a brief description by analyzing the content
|
||||||
- Create a relative markdown link to the file
|
- Create a relative markdown link to the file
|
||||||
|
|
@ -35,7 +32,6 @@ You are now operating as a Documentation Indexer. Your goal is to ensure all doc
|
||||||
- If missing or outdated, prepare an update
|
- If missing or outdated, prepare an update
|
||||||
|
|
||||||
4. For any missing or non-existent files found in index:
|
4. For any missing or non-existent files found in index:
|
||||||
|
|
||||||
- Present a list of all entries that reference non-existent files
|
- Present a list of all entries that reference non-existent files
|
||||||
- For each entry:
|
- For each entry:
|
||||||
- Show the full entry details (title, path, description)
|
- Show the full entry details (title, path, description)
|
||||||
|
|
@ -88,7 +84,6 @@ Documents within the `another-folder/` directory:
|
||||||
### [Nested Document](./another-folder/document.md)
|
### [Nested Document](./another-folder/document.md)
|
||||||
|
|
||||||
Description of nested document.
|
Description of nested document.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Index Entry Format
|
### Index Entry Format
|
||||||
|
|
@ -157,7 +152,6 @@ For each file referenced in the index but not found in the filesystem:
|
||||||
### Special Cases
|
### Special Cases
|
||||||
|
|
||||||
1. **Sharded Documents**: If a folder contains an `index.md` file, treat it as a sharded document:
|
1. **Sharded Documents**: If a folder contains an `index.md` file, treat it as a sharded document:
|
||||||
|
|
||||||
- Use the folder's `index.md` title as the section title
|
- Use the folder's `index.md` title as the section title
|
||||||
- List the folder's documents as subsections
|
- List the folder's documents as subsections
|
||||||
- Note in the description that this is a multi-part document
|
- Note in the description that this is a multi-part document
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Provide a user-friendly interface to the BMad knowledge base without overwhelmin
|
||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
|
|
||||||
When entering KB mode (*kb-mode), follow these steps:
|
When entering KB mode (\*kb-mode), follow these steps:
|
||||||
|
|
||||||
### 1. Welcome and Guide
|
### 1. Welcome and Guide
|
||||||
|
|
||||||
|
|
@ -48,12 +48,12 @@ Or ask me about anything else related to BMad-Method!
|
||||||
When user is done or wants to exit KB mode:
|
When user is done or wants to exit KB mode:
|
||||||
|
|
||||||
- Summarize key points discussed if helpful
|
- Summarize key points discussed if helpful
|
||||||
- Remind them they can return to KB mode anytime with *kb-mode
|
- Remind them they can return to KB mode anytime with \*kb-mode
|
||||||
- Suggest next steps based on what was discussed
|
- Suggest next steps based on what was discussed
|
||||||
|
|
||||||
## Example Interaction
|
## Example Interaction
|
||||||
|
|
||||||
**User**: *kb-mode
|
**User**: \*kb-mode
|
||||||
|
|
||||||
**Assistant**: I've entered KB mode and have access to the full BMad knowledge base. I can help you with detailed information about any aspect of BMad-Method.
|
**Assistant**: I've entered KB mode and have access to the full BMad knowledge base. I can help you with detailed information about any aspect of BMad-Method.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,25 +81,31 @@ After review and any refactoring, append your results to the story file in the Q
|
||||||
## QA Results
|
## QA Results
|
||||||
|
|
||||||
### Review Date: [Date]
|
### Review Date: [Date]
|
||||||
|
|
||||||
### Reviewed By: Quinn (Senior Developer QA)
|
### Reviewed By: Quinn (Senior Developer QA)
|
||||||
|
|
||||||
### Code Quality Assessment
|
### Code Quality Assessment
|
||||||
|
|
||||||
[Overall assessment of implementation quality]
|
[Overall assessment of implementation quality]
|
||||||
|
|
||||||
### Refactoring Performed
|
### Refactoring Performed
|
||||||
|
|
||||||
[List any refactoring you performed with explanations]
|
[List any refactoring you performed with explanations]
|
||||||
|
|
||||||
- **File**: [filename]
|
- **File**: [filename]
|
||||||
- **Change**: [what was changed]
|
- **Change**: [what was changed]
|
||||||
- **Why**: [reason for change]
|
- **Why**: [reason for change]
|
||||||
- **How**: [how it improves the code]
|
- **How**: [how it improves the code]
|
||||||
|
|
||||||
### Compliance Check
|
### Compliance Check
|
||||||
|
|
||||||
- Coding Standards: [✓/✗] [notes if any]
|
- Coding Standards: [✓/✗] [notes if any]
|
||||||
- Project Structure: [✓/✗] [notes if any]
|
- Project Structure: [✓/✗] [notes if any]
|
||||||
- Testing Strategy: [✓/✗] [notes if any]
|
- Testing Strategy: [✓/✗] [notes if any]
|
||||||
- All ACs Met: [✓/✗] [notes if any]
|
- All ACs Met: [✓/✗] [notes if any]
|
||||||
|
|
||||||
### Improvements Checklist
|
### Improvements Checklist
|
||||||
|
|
||||||
[Check off items you handled yourself, leave unchecked for dev to address]
|
[Check off items you handled yourself, leave unchecked for dev to address]
|
||||||
|
|
||||||
- [x] Refactored user service for better error handling (services/user.service.ts)
|
- [x] Refactored user service for better error handling (services/user.service.ts)
|
||||||
|
|
@ -109,12 +115,15 @@ After review and any refactoring, append your results to the story file in the Q
|
||||||
- [ ] Update API documentation for new error codes
|
- [ ] Update API documentation for new error codes
|
||||||
|
|
||||||
### Security Review
|
### Security Review
|
||||||
|
|
||||||
[Any security concerns found and whether addressed]
|
[Any security concerns found and whether addressed]
|
||||||
|
|
||||||
### Performance Considerations
|
### Performance Considerations
|
||||||
|
|
||||||
[Any performance issues found and whether addressed]
|
[Any performance issues found and whether addressed]
|
||||||
|
|
||||||
### Final Status
|
### Final Status
|
||||||
|
|
||||||
[✓ Approved - Ready for Done] / [✗ Changes Required - See unchecked items above]
|
[✓ Approved - Ready for Done] / [✗ Changes Required - See unchecked items above]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,13 +91,11 @@ CRITICAL: Use proper parsing that understands markdown context. A ## inside a co
|
||||||
For each extracted section:
|
For each extracted section:
|
||||||
|
|
||||||
1. **Generate filename**: Convert the section heading to lowercase-dash-case
|
1. **Generate filename**: Convert the section heading to lowercase-dash-case
|
||||||
|
|
||||||
- Remove special characters
|
- Remove special characters
|
||||||
- Replace spaces with dashes
|
- Replace spaces with dashes
|
||||||
- Example: "## Tech Stack" → `tech-stack.md`
|
- Example: "## Tech Stack" → `tech-stack.md`
|
||||||
|
|
||||||
2. **Adjust heading levels**:
|
2. **Adjust heading levels**:
|
||||||
|
|
||||||
- The level 2 heading becomes level 1 (# instead of ##) in the sharded new document
|
- The level 2 heading becomes level 1 (# instead of ##) in the sharded new document
|
||||||
- All subsection levels decrease by 1:
|
- All subsection levels decrease by 1:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,14 @@ sections:
|
||||||
title: Feature Comparison Matrix
|
title: Feature Comparison Matrix
|
||||||
instruction: Create a detailed comparison table of key features across competitors
|
instruction: Create a detailed comparison table of key features across competitors
|
||||||
type: table
|
type: table
|
||||||
columns: ["Feature Category", "{{your_company}}", "{{competitor_1}}", "{{competitor_2}}", "{{competitor_3}}"]
|
columns:
|
||||||
|
[
|
||||||
|
"Feature Category",
|
||||||
|
"{{your_company}}",
|
||||||
|
"{{competitor_1}}",
|
||||||
|
"{{competitor_2}}",
|
||||||
|
"{{competitor_3}}",
|
||||||
|
]
|
||||||
rows:
|
rows:
|
||||||
- category: "Core Functionality"
|
- category: "Core Functionality"
|
||||||
items:
|
items:
|
||||||
|
|
@ -153,7 +160,13 @@ sections:
|
||||||
- ["Onboarding Time", "{{time}}", "{{time}}", "{{time}}", "{{time}}"]
|
- ["Onboarding Time", "{{time}}", "{{time}}", "{{time}}", "{{time}}"]
|
||||||
- category: "Integration & Ecosystem"
|
- category: "Integration & Ecosystem"
|
||||||
items:
|
items:
|
||||||
- ["API Availability", "{{availability}}", "{{availability}}", "{{availability}}", "{{availability}}"]
|
- [
|
||||||
|
"API Availability",
|
||||||
|
"{{availability}}",
|
||||||
|
"{{availability}}",
|
||||||
|
"{{availability}}",
|
||||||
|
"{{availability}}",
|
||||||
|
]
|
||||||
- ["Third-party Integrations", "{{number}}", "{{number}}", "{{number}}", "{{number}}"]
|
- ["Third-party Integrations", "{{number}}", "{{number}}", "{{number}}", "{{number}}"]
|
||||||
- category: "Pricing & Plans"
|
- category: "Pricing & Plans"
|
||||||
items:
|
items:
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,24 @@ sections:
|
||||||
rows:
|
rows:
|
||||||
- ["Framework", "{{framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Framework", "{{framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["UI Library", "{{ui_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["UI Library", "{{ui_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["State Management", "{{state_management}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- [
|
||||||
|
"State Management",
|
||||||
|
"{{state_management}}",
|
||||||
|
"{{version}}",
|
||||||
|
"{{purpose}}",
|
||||||
|
"{{why_chosen}}",
|
||||||
|
]
|
||||||
- ["Routing", "{{routing_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Routing", "{{routing_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Build Tool", "{{build_tool}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Build Tool", "{{build_tool}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Styling", "{{styling_solution}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Styling", "{{styling_solution}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Testing", "{{test_framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Testing", "{{test_framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Component Library", "{{component_lib}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- [
|
||||||
|
"Component Library",
|
||||||
|
"{{component_lib}}",
|
||||||
|
"{{version}}",
|
||||||
|
"{{purpose}}",
|
||||||
|
"{{why_chosen}}",
|
||||||
|
]
|
||||||
- ["Form Handling", "{{form_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Form Handling", "{{form_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Animation", "{{animation_lib}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Animation", "{{animation_lib}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Dev Tools", "{{dev_tools}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Dev Tools", "{{dev_tools}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
|
|
|
||||||
|
|
@ -156,11 +156,29 @@ sections:
|
||||||
columns: [Category, Technology, Version, Purpose, Rationale]
|
columns: [Category, Technology, Version, Purpose, Rationale]
|
||||||
rows:
|
rows:
|
||||||
- ["Frontend Language", "{{fe_language}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Frontend Language", "{{fe_language}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Frontend Framework", "{{fe_framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- [
|
||||||
- ["UI Component Library", "{{ui_library}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
"Frontend Framework",
|
||||||
|
"{{fe_framework}}",
|
||||||
|
"{{version}}",
|
||||||
|
"{{purpose}}",
|
||||||
|
"{{why_chosen}}",
|
||||||
|
]
|
||||||
|
- [
|
||||||
|
"UI Component Library",
|
||||||
|
"{{ui_library}}",
|
||||||
|
"{{version}}",
|
||||||
|
"{{purpose}}",
|
||||||
|
"{{why_chosen}}",
|
||||||
|
]
|
||||||
- ["State Management", "{{state_mgmt}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["State Management", "{{state_mgmt}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Backend Language", "{{be_language}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Backend Language", "{{be_language}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Backend Framework", "{{be_framework}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- [
|
||||||
|
"Backend Framework",
|
||||||
|
"{{be_framework}}",
|
||||||
|
"{{version}}",
|
||||||
|
"{{purpose}}",
|
||||||
|
"{{why_chosen}}",
|
||||||
|
]
|
||||||
- ["API Style", "{{api_style}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["API Style", "{{api_style}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Database", "{{database}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Database", "{{database}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
- ["Cache", "{{cache}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
- ["Cache", "{{cache}}", "{{version}}", "{{purpose}}", "{{why_chosen}}"]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ If the user asks or does not specify a specific checklist, list the checklists a
|
||||||
## Instructions
|
## Instructions
|
||||||
|
|
||||||
1. **Initial Assessment**
|
1. **Initial Assessment**
|
||||||
|
|
||||||
- If user or the task being run provides a checklist name:
|
- If user or the task being run provides a checklist name:
|
||||||
- Try fuzzy matching (e.g. "architecture checklist" -> "architect-checklist")
|
- Try fuzzy matching (e.g. "architecture checklist" -> "architect-checklist")
|
||||||
- If multiple matches found, ask user to clarify
|
- If multiple matches found, ask user to clarify
|
||||||
|
|
@ -22,14 +21,12 @@ If the user asks or does not specify a specific checklist, list the checklists a
|
||||||
- All at once (YOLO mode - recommended for checklists, there will be a summary of sections at the end to discuss)
|
- All at once (YOLO mode - recommended for checklists, there will be a summary of sections at the end to discuss)
|
||||||
|
|
||||||
2. **Document and Artifact Gathering**
|
2. **Document and Artifact Gathering**
|
||||||
|
|
||||||
- Each checklist will specify its required documents/artifacts at the beginning
|
- Each checklist will specify its required documents/artifacts at the beginning
|
||||||
- Follow the checklist's specific instructions for what to gather, generally a file can be resolved in the docs folder, if not or unsure, halt and ask or confirm with the user.
|
- Follow the checklist's specific instructions for what to gather, generally a file can be resolved in the docs folder, if not or unsure, halt and ask or confirm with the user.
|
||||||
|
|
||||||
3. **Checklist Processing**
|
3. **Checklist Processing**
|
||||||
|
|
||||||
If in interactive mode:
|
If in interactive mode:
|
||||||
|
|
||||||
- Work through each section of the checklist one at a time
|
- Work through each section of the checklist one at a time
|
||||||
- For each section:
|
- For each section:
|
||||||
- Review all items in the section following instructions for that section embedded in the checklist
|
- Review all items in the section following instructions for that section embedded in the checklist
|
||||||
|
|
@ -38,7 +35,6 @@ If the user asks or does not specify a specific checklist, list the checklists a
|
||||||
- Get user confirmation before proceeding to next section or if any thing major do we need to halt and take corrective action
|
- Get user confirmation before proceeding to next section or if any thing major do we need to halt and take corrective action
|
||||||
|
|
||||||
If in YOLO mode:
|
If in YOLO mode:
|
||||||
|
|
||||||
- Process all sections at once
|
- Process all sections at once
|
||||||
- Create a comprehensive report of all findings
|
- Create a comprehensive report of all findings
|
||||||
- Present the complete analysis to the user
|
- Present the complete analysis to the user
|
||||||
|
|
@ -46,7 +42,6 @@ If the user asks or does not specify a specific checklist, list the checklists a
|
||||||
4. **Validation Approach**
|
4. **Validation Approach**
|
||||||
|
|
||||||
For each checklist item:
|
For each checklist item:
|
||||||
|
|
||||||
- Read and understand the requirement
|
- Read and understand the requirement
|
||||||
- Look for evidence in the documentation that satisfies the requirement
|
- Look for evidence in the documentation that satisfies the requirement
|
||||||
- Consider both explicit mentions and implicit coverage
|
- Consider both explicit mentions and implicit coverage
|
||||||
|
|
@ -60,7 +55,6 @@ If the user asks or does not specify a specific checklist, list the checklists a
|
||||||
5. **Section Analysis**
|
5. **Section Analysis**
|
||||||
|
|
||||||
For each section:
|
For each section:
|
||||||
|
|
||||||
- think step by step to calculate pass rate
|
- think step by step to calculate pass rate
|
||||||
- Identify common themes in failed items
|
- Identify common themes in failed items
|
||||||
- Provide specific recommendations for improvement
|
- Provide specific recommendations for improvement
|
||||||
|
|
@ -70,7 +64,6 @@ If the user asks or does not specify a specific checklist, list the checklists a
|
||||||
6. **Final Report**
|
6. **Final Report**
|
||||||
|
|
||||||
Prepare a summary that includes:
|
Prepare a summary that includes:
|
||||||
|
|
||||||
- Overall checklist completion status
|
- Overall checklist completion status
|
||||||
- Pass rates by section
|
- Pass rates by section
|
||||||
- List of failed items with context
|
- List of failed items with context
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ template:
|
||||||
output:
|
output:
|
||||||
format: markdown
|
format: markdown
|
||||||
filename: default-path/to/{{filename}}.md
|
filename: default-path/to/{{filename}}.md
|
||||||
title: "{{variable}} Document Title"
|
title: '{{variable}} Document Title'
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
mode: interactive
|
mode: interactive
|
||||||
|
|
@ -108,8 +108,8 @@ sections:
|
||||||
Use `{{variable_name}}` in titles, templates, and content:
|
Use `{{variable_name}}` in titles, templates, and content:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
title: "Epic {{epic_number}} {{epic_title}}"
|
title: 'Epic {{epic_number}} {{epic_title}}'
|
||||||
template: "As a {{user_type}}, I want {{action}}, so that {{benefit}}."
|
template: 'As a {{user_type}}, I want {{action}}, so that {{benefit}}.'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Conditional Sections
|
### Conditional Sections
|
||||||
|
|
@ -212,7 +212,7 @@ choices:
|
||||||
- id: criteria
|
- id: criteria
|
||||||
title: Acceptance Criteria
|
title: Acceptance Criteria
|
||||||
type: numbered-list
|
type: numbered-list
|
||||||
item_template: "{{criterion_number}}: {{criteria}}"
|
item_template: '{{criterion_number}}: {{criteria}}'
|
||||||
repeatable: true
|
repeatable: true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -220,7 +220,7 @@ choices:
|
||||||
|
|
||||||
````yaml
|
````yaml
|
||||||
examples:
|
examples:
|
||||||
- "FR6: The system must authenticate users within 2 seconds"
|
- 'FR6: The system must authenticate users within 2 seconds'
|
||||||
- |
|
- |
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
|
|
|
||||||
|
|
@ -2337,7 +2337,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -8068,7 +8068,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -775,7 +775,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -3733,7 +3733,7 @@ Use the `shard-doc` task or `@kayvan/markdown-tree-parser` tool for automatic ga
|
||||||
|
|
||||||
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Windsurf**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Windsurf**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
||||||
|
|
|
||||||
|
|
@ -3430,7 +3430,7 @@ Use the `shard-doc` task or `@kayvan/markdown-tree-parser` tool for automatic ga
|
||||||
|
|
||||||
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Windsurf**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Windsurf**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
||||||
|
|
|
||||||
|
|
@ -2874,7 +2874,7 @@ Use the `shard-doc` task or `@kayvan/markdown-tree-parser` tool for automatic ga
|
||||||
|
|
||||||
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Windsurf**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Windsurf**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
||||||
|
|
@ -14560,7 +14560,7 @@ Use the `shard-doc` task or `@kayvan/markdown-tree-parser` tool for automatic ga
|
||||||
|
|
||||||
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Windsurf**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Windsurf**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
||||||
|
|
|
||||||
|
|
@ -1242,7 +1242,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -1098,7 +1098,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -995,7 +995,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -1044,7 +1044,7 @@ You are the "Vibe CEO" - thinking like a CEO with unlimited resources and a sing
|
||||||
|
|
||||||
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
- **Windsurf**: `/agent-name` (e.g., `/bmad-master`)
|
||||||
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
||||||
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-master`)
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select **Agent** from the chat mode selector.
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ If you have just completed an MVP with BMad, and you want to continue with post-
|
||||||
## The Complete Brownfield Workflow
|
## The Complete Brownfield Workflow
|
||||||
|
|
||||||
1. **Follow the [<ins>User Guide - Installation</ins>](user-guide.md#installation) steps to setup your agent in the web.**
|
1. **Follow the [<ins>User Guide - Installation</ins>](user-guide.md#installation) steps to setup your agent in the web.**
|
||||||
2. **Generate a 'flattened' single file of your entire codebase** run: ```npx bmad-method flatten```
|
2. **Generate a 'flattened' single file of your entire codebase** run: `npx bmad-method flatten`
|
||||||
|
|
||||||
### Choose Your Approach
|
### Choose Your Approach
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
import js from '@eslint/js';
|
||||||
|
import nodePlugin from 'eslint-plugin-n';
|
||||||
|
import yml from 'eslint-plugin-yml';
|
||||||
|
import unicorn from 'eslint-plugin-unicorn';
|
||||||
|
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
// Global ignores for files/folders that should not be linted
|
||||||
|
{
|
||||||
|
ignores: ['dist/**', 'coverage/**', '**/*.min.js'],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Base JavaScript recommended rules
|
||||||
|
js.configs.recommended,
|
||||||
|
|
||||||
|
// Node.js rules
|
||||||
|
...nodePlugin.configs['flat/mixed-esm-and-cjs'],
|
||||||
|
|
||||||
|
// Unicorn rules (modern best practices)
|
||||||
|
unicorn.configs.recommended,
|
||||||
|
|
||||||
|
// YAML linting
|
||||||
|
...yml.configs['flat/recommended'],
|
||||||
|
|
||||||
|
// Place Prettier last to disable conflicting stylistic rules
|
||||||
|
eslintConfigPrettier,
|
||||||
|
|
||||||
|
// Project-specific tweaks
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
// Allow console for CLI tools in this repo
|
||||||
|
'no-console': 'off',
|
||||||
|
// Do not enforce a specific YAML file extension (.yml vs .yaml)
|
||||||
|
'yml/file-extension': 'off',
|
||||||
|
// Relax some Unicorn rules that are too opinionated for this codebase
|
||||||
|
'unicorn/prevent-abbreviations': 'off',
|
||||||
|
'unicorn/no-null': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// CLI/CommonJS scripts under tools/**
|
||||||
|
{
|
||||||
|
files: ['tools/**/*.js'],
|
||||||
|
rules: {
|
||||||
|
// Allow CommonJS patterns for Node CLI scripts
|
||||||
|
'unicorn/prefer-module': 'off',
|
||||||
|
'unicorn/import-style': 'off',
|
||||||
|
'unicorn/no-process-exit': 'off',
|
||||||
|
'n/no-process-exit': 'off',
|
||||||
|
'unicorn/no-await-expression-member': 'off',
|
||||||
|
'unicorn/prefer-top-level-await': 'off',
|
||||||
|
// Avoid failing CI on incidental unused vars in internal scripts
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
// Reduce style-only churn in internal tools
|
||||||
|
'unicorn/prefer-ternary': 'off',
|
||||||
|
'unicorn/filename-case': 'off',
|
||||||
|
'unicorn/no-array-reduce': 'off',
|
||||||
|
'unicorn/no-array-callback-reference': 'off',
|
||||||
|
'unicorn/consistent-function-scoping': 'off',
|
||||||
|
'n/no-extraneous-require': 'off',
|
||||||
|
'n/no-extraneous-import': 'off',
|
||||||
|
'n/no-unpublished-require': 'off',
|
||||||
|
'n/no-unpublished-import': 'off',
|
||||||
|
// Some scripts intentionally use globals provided at runtime
|
||||||
|
'no-undef': 'off',
|
||||||
|
// Additional relaxed rules for legacy/internal scripts
|
||||||
|
'no-useless-catch': 'off',
|
||||||
|
'unicorn/prefer-number-properties': 'off',
|
||||||
|
'no-unreachable': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ESLint config file should not be checked for publish-related Node rules
|
||||||
|
{
|
||||||
|
files: ['eslint.config.mjs'],
|
||||||
|
rules: {
|
||||||
|
'n/no-unpublished-import': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// YAML workflow templates allow empty mapping values intentionally
|
||||||
|
{
|
||||||
|
files: ['bmad-core/workflows/**/*.{yml,yaml}'],
|
||||||
|
rules: {
|
||||||
|
'yml/no-empty-mapping-value': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// GitHub workflow files in this repo may use empty mapping values
|
||||||
|
{
|
||||||
|
files: ['.github/workflows/**/*.{yml,yaml}'],
|
||||||
|
rules: {
|
||||||
|
'yml/no-empty-mapping-value': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Other GitHub YAML files may intentionally use empty values and reserved filenames
|
||||||
|
{
|
||||||
|
files: ['.github/**/*.{yml,yaml}'],
|
||||||
|
rules: {
|
||||||
|
'yml/no-empty-mapping-value': 'off',
|
||||||
|
'unicorn/filename-case': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
steps:
|
steps:
|
||||||
# Build the container image
|
# Build the container image
|
||||||
- name: 'gcr.io/cloud-builders/docker'
|
- name: "gcr.io/cloud-builders/docker"
|
||||||
args: ['build', '-t', 'gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA', '.']
|
args: ["build", "-t", "gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA", "."]
|
||||||
|
|
||||||
# Push the container image to Container Registry
|
# Push the container image to Container Registry
|
||||||
- name: 'gcr.io/cloud-builders/docker'
|
- name: "gcr.io/cloud-builders/docker"
|
||||||
args: ['push', 'gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA']
|
args: ["push", "gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA"]
|
||||||
|
|
||||||
# Deploy container image to Cloud Run
|
# Deploy container image to Cloud Run
|
||||||
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
- name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
|
||||||
entrypoint: gcloud
|
entrypoint: gcloud
|
||||||
args:
|
args:
|
||||||
- 'run'
|
- "run"
|
||||||
- 'deploy'
|
- "deploy"
|
||||||
- '{{COMPANY_NAME}}-ai-agents'
|
- "{{COMPANY_NAME}}-ai-agents"
|
||||||
- '--image'
|
- "--image"
|
||||||
- 'gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA'
|
- "gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA"
|
||||||
- '--region'
|
- "--region"
|
||||||
- '{{LOCATION}}'
|
- "{{LOCATION}}"
|
||||||
- '--platform'
|
- "--platform"
|
||||||
- 'managed'
|
- "managed"
|
||||||
- '--allow-unauthenticated'
|
- "--allow-unauthenticated"
|
||||||
|
|
||||||
images:
|
images:
|
||||||
- 'gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA'
|
- "gcr.io/{{PROJECT_ID}}/{{COMPANY_NAME}}-ai-agents:$COMMIT_SHA"
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,21 @@ This expansion pack provides a complete, deployable starter kit for building and
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* **Automated GCP Setup**: `gcloud` scripts to configure your project, service accounts, and required APIs in minutes.
|
- **Automated GCP Setup**: `gcloud` scripts to configure your project, service accounts, and required APIs in minutes.
|
||||||
* **Production-Ready Deployment**: Includes a `Dockerfile` and `cloudbuild.yaml` for easy, repeatable deployments to Google Cloud Run.
|
- **Production-Ready Deployment**: Includes a `Dockerfile` and `cloudbuild.yaml` for easy, repeatable deployments to Google Cloud Run.
|
||||||
* **Rich Template Library**: A comprehensive set of BMad-compatible templates for Teams, Agents, Tasks, Workflows, Documents, and Checklists.
|
- **Rich Template Library**: A comprehensive set of BMad-compatible templates for Teams, Agents, Tasks, Workflows, Documents, and Checklists.
|
||||||
* **Pre-configured Agent Roles**: Includes powerful master templates for key agent archetypes like Orchestrators and Specialists.
|
- **Pre-configured Agent Roles**: Includes powerful master templates for key agent archetypes like Orchestrators and Specialists.
|
||||||
* **Highly Customizable**: Easily adapt the entire system with company-specific variables and industry-specific configurations.
|
- **Highly Customizable**: Easily adapt the entire system with company-specific variables and industry-specific configurations.
|
||||||
* **Powered by Google ADK**: Built on the official Google Agent Development Kit for robust and native integration with Vertex AI services.
|
- **Powered by Google ADK**: Built on the official Google Agent Development Kit for robust and native integration with Vertex AI services.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
Before you begin, ensure you have the following installed and configured:
|
Before you begin, ensure you have the following installed and configured:
|
||||||
|
|
||||||
* A Google Cloud Platform (GCP) Account with an active billing account.
|
- A Google Cloud Platform (GCP) Account with an active billing account.
|
||||||
* The [Google Cloud SDK (`gcloud` CLI)](https://www.google.com/search?q=%5Bhttps://cloud.google.com/sdk/docs/install%5D\(https://cloud.google.com/sdk/docs/install\)) installed and authenticated.
|
- The [Google Cloud SDK (`gcloud` CLI)](<https://www.google.com/search?q=%5Bhttps://cloud.google.com/sdk/docs/install%5D(https://cloud.google.com/sdk/docs/install)>) installed and authenticated.
|
||||||
* [Docker](https://www.docker.com/products/docker-desktop/) installed on your local machine.
|
- [Docker](https://www.docker.com/products/docker-desktop/) installed on your local machine.
|
||||||
* Python 3.11+
|
- Python 3.11+
|
||||||
|
|
||||||
## Quick Start Guide
|
## Quick Start Guide
|
||||||
|
|
||||||
|
|
@ -32,9 +32,9 @@ Follow these steps to get your own AI agent system running on Google Cloud.
|
||||||
|
|
||||||
The setup scripts use placeholder variables. Before running them, open the files in the `/scripts` directory and replace the following placeholders with your own values:
|
The setup scripts use placeholder variables. Before running them, open the files in the `/scripts` directory and replace the following placeholders with your own values:
|
||||||
|
|
||||||
* `{{PROJECT_ID}}`: Your unique Google Cloud project ID.
|
- `{{PROJECT_ID}}`: Your unique Google Cloud project ID.
|
||||||
* `{{COMPANY_NAME}}`: Your company or project name (used for naming resources).
|
- `{{COMPANY_NAME}}`: Your company or project name (used for naming resources).
|
||||||
* `{{LOCATION}}`: The GCP region you want to deploy to (e.g., `us-central1`).
|
- `{{LOCATION}}`: The GCP region you want to deploy to (e.g., `us-central1`).
|
||||||
|
|
||||||
### 2\. Run the GCP Setup Scripts
|
### 2\. Run the GCP Setup Scripts
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ commands:
|
||||||
task-execution:
|
task-execution:
|
||||||
flow: Read story → Implement game feature → Write tests → Pass tests → Update [x] → Next task
|
flow: Read story → Implement game feature → Write tests → Pass tests → Update [x] → Next task
|
||||||
updates-ONLY:
|
updates-ONLY:
|
||||||
- "Checkboxes: [ ] not started | [-] in progress | [x] complete"
|
- 'Checkboxes: [ ] not started | [-] in progress | [x] complete'
|
||||||
- "Debug Log: | Task | File | Change | Reverted? |"
|
- 'Debug Log: | Task | File | Change | Reverted? |'
|
||||||
- "Completion Notes: Deviations only, <50 words"
|
- 'Completion Notes: Deviations only, <50 words'
|
||||||
- "Change Log: Requirement changes only"
|
- 'Change Log: Requirement changes only'
|
||||||
blocking: Unapproved deps | Ambiguous after story check | 3 failures | Missing game config
|
blocking: Unapproved deps | Ambiguous after story check | 3 failures | Missing game config
|
||||||
done: Game feature works + Tests pass + 60 FPS + No lint errors + Follows Phaser 3 best practices
|
done: Game feature works + Tests pass + 60 FPS + No lint errors + Follows Phaser 3 best practices
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ activation-instructions:
|
||||||
- When listing tasks/templates or presenting options during conversations, always show as numbered options list, allowing the user to type a number to select or execute
|
- When listing tasks/templates or presenting options during conversations, always show as numbered options list, allowing the user to type a number to select or execute
|
||||||
- STAY IN CHARACTER!
|
- STAY IN CHARACTER!
|
||||||
- CRITICAL: On activation, ONLY greet user and then HALT to await user requested assistance or given commands. ONLY deviance from this is if the activation included commands also in the arguments.
|
- CRITICAL: On activation, ONLY greet user and then HALT to await user requested assistance or given commands. ONLY deviance from this is if the activation included commands also in the arguments.
|
||||||
- "CRITICAL RULE: You are ONLY allowed to create/modify story files - NEVER implement! If asked to implement, tell user they MUST switch to Game Developer Agent"
|
- 'CRITICAL RULE: You are ONLY allowed to create/modify story files - NEVER implement! If asked to implement, tell user they MUST switch to Game Developer Agent'
|
||||||
agent:
|
agent:
|
||||||
name: Jordan
|
name: Jordan
|
||||||
id: game-sm
|
id: game-sm
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,11 @@ You are developing games as a "Player Experience CEO" - thinking like a game dir
|
||||||
### Phase 1: Game Concept and Design
|
### Phase 1: Game Concept and Design
|
||||||
|
|
||||||
1. **Game Designer**: Start with brainstorming and concept development
|
1. **Game Designer**: Start with brainstorming and concept development
|
||||||
|
|
||||||
- Use \*brainstorm to explore game concepts and mechanics
|
- Use \*brainstorm to explore game concepts and mechanics
|
||||||
- Create Game Brief using game-brief-tmpl
|
- Create Game Brief using game-brief-tmpl
|
||||||
- Develop core game pillars and player experience goals
|
- Develop core game pillars and player experience goals
|
||||||
|
|
||||||
2. **Game Designer**: Create comprehensive Game Design Document
|
2. **Game Designer**: Create comprehensive Game Design Document
|
||||||
|
|
||||||
- Use game-design-doc-tmpl to create detailed GDD
|
- Use game-design-doc-tmpl to create detailed GDD
|
||||||
- Define all game mechanics, progression, and balance
|
- Define all game mechanics, progression, and balance
|
||||||
- Specify technical requirements and platform targets
|
- Specify technical requirements and platform targets
|
||||||
|
|
@ -65,13 +63,11 @@ You are developing games as a "Player Experience CEO" - thinking like a game dir
|
||||||
### Phase 3: Story-Driven Development
|
### Phase 3: Story-Driven Development
|
||||||
|
|
||||||
5. **Game Scrum Master**: Break down design into development stories
|
5. **Game Scrum Master**: Break down design into development stories
|
||||||
|
|
||||||
- Use create-game-story task to create detailed implementation stories
|
- Use create-game-story task to create detailed implementation stories
|
||||||
- Each story should be immediately actionable by game developers
|
- Each story should be immediately actionable by game developers
|
||||||
- Apply game-story-dod-checklist to ensure story quality
|
- Apply game-story-dod-checklist to ensure story quality
|
||||||
|
|
||||||
6. **Game Developer**: Implement game features story by story
|
6. **Game Developer**: Implement game features story by story
|
||||||
|
|
||||||
- Follow TypeScript strict mode and Phaser 3 best practices
|
- Follow TypeScript strict mode and Phaser 3 best practices
|
||||||
- Maintain 60 FPS performance target throughout development
|
- Maintain 60 FPS performance target throughout development
|
||||||
- Use test-driven development for game logic components
|
- Use test-driven development for game logic components
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ interface GameState {
|
||||||
interface GameSettings {
|
interface GameSettings {
|
||||||
musicVolume: number;
|
musicVolume: number;
|
||||||
sfxVolume: number;
|
sfxVolume: number;
|
||||||
difficulty: "easy" | "normal" | "hard";
|
difficulty: 'easy' | 'normal' | 'hard';
|
||||||
controls: ControlScheme;
|
controls: ControlScheme;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -114,12 +114,12 @@ class GameScene extends Phaser.Scene {
|
||||||
private inputManager!: InputManager;
|
private inputManager!: InputManager;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({ key: "GameScene" });
|
super({ key: 'GameScene' });
|
||||||
}
|
}
|
||||||
|
|
||||||
preload(): void {
|
preload(): void {
|
||||||
// Load only scene-specific assets
|
// Load only scene-specific assets
|
||||||
this.load.image("player", "assets/player.png");
|
this.load.image('player', 'assets/player.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
create(data: SceneData): void {
|
create(data: SceneData): void {
|
||||||
|
|
@ -144,7 +144,7 @@ class GameScene extends Phaser.Scene {
|
||||||
this.inputManager.destroy();
|
this.inputManager.destroy();
|
||||||
|
|
||||||
// Remove event listeners
|
// Remove event listeners
|
||||||
this.events.off("*");
|
this.events.off('*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -153,13 +153,13 @@ class GameScene extends Phaser.Scene {
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Proper scene transitions with data
|
// Proper scene transitions with data
|
||||||
this.scene.start("NextScene", {
|
this.scene.start('NextScene', {
|
||||||
playerScore: this.playerScore,
|
playerScore: this.playerScore,
|
||||||
currentLevel: this.currentLevel + 1,
|
currentLevel: this.currentLevel + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scene overlays for UI
|
// Scene overlays for UI
|
||||||
this.scene.launch("PauseMenuScene");
|
this.scene.launch('PauseMenuScene');
|
||||||
this.scene.pause();
|
this.scene.pause();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -203,7 +203,7 @@ class Player extends GameEntity {
|
||||||
private health!: HealthComponent;
|
private health!: HealthComponent;
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, x: number, y: number) {
|
constructor(scene: Phaser.Scene, x: number, y: number) {
|
||||||
super(scene, x, y, "player");
|
super(scene, x, y, 'player');
|
||||||
|
|
||||||
this.movement = this.addComponent(new MovementComponent(this));
|
this.movement = this.addComponent(new MovementComponent(this));
|
||||||
this.health = this.addComponent(new HealthComponent(this, 100));
|
this.health = this.addComponent(new HealthComponent(this, 100));
|
||||||
|
|
@ -223,7 +223,7 @@ class GameManager {
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene) {
|
constructor(scene: Phaser.Scene) {
|
||||||
if (GameManager.instance) {
|
if (GameManager.instance) {
|
||||||
throw new Error("GameManager already exists!");
|
throw new Error('GameManager already exists!');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
@ -233,7 +233,7 @@ class GameManager {
|
||||||
|
|
||||||
static getInstance(): GameManager {
|
static getInstance(): GameManager {
|
||||||
if (!GameManager.instance) {
|
if (!GameManager.instance) {
|
||||||
throw new Error("GameManager not initialized!");
|
throw new Error('GameManager not initialized!');
|
||||||
}
|
}
|
||||||
return GameManager.instance;
|
return GameManager.instance;
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +280,7 @@ class BulletPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool exhausted - create new bullet
|
// Pool exhausted - create new bullet
|
||||||
console.warn("Bullet pool exhausted, creating new bullet");
|
console.warn('Bullet pool exhausted, creating new bullet');
|
||||||
return new Bullet(this.scene, 0, 0);
|
return new Bullet(this.scene, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,12 +380,12 @@ class InputManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupKeyboard(): void {
|
private setupKeyboard(): void {
|
||||||
this.keys = this.scene.input.keyboard.addKeys("W,A,S,D,SPACE,ESC,UP,DOWN,LEFT,RIGHT");
|
this.keys = this.scene.input.keyboard.addKeys('W,A,S,D,SPACE,ESC,UP,DOWN,LEFT,RIGHT');
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupTouch(): void {
|
private setupTouch(): void {
|
||||||
this.scene.input.on("pointerdown", this.handlePointerDown, this);
|
this.scene.input.on('pointerdown', this.handlePointerDown, this);
|
||||||
this.scene.input.on("pointerup", this.handlePointerUp, this);
|
this.scene.input.on('pointerup', this.handlePointerUp, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(): void {
|
update(): void {
|
||||||
|
|
@ -412,9 +412,9 @@ class InputManager {
|
||||||
class AssetManager {
|
class AssetManager {
|
||||||
loadAssets(): Promise<void> {
|
loadAssets(): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.scene.load.on("filecomplete", this.handleFileComplete, this);
|
this.scene.load.on('filecomplete', this.handleFileComplete, this);
|
||||||
this.scene.load.on("loaderror", this.handleLoadError, this);
|
this.scene.load.on('loaderror', this.handleLoadError, this);
|
||||||
this.scene.load.on("complete", () => resolve());
|
this.scene.load.on('complete', () => resolve());
|
||||||
|
|
||||||
this.scene.load.start();
|
this.scene.load.start();
|
||||||
});
|
});
|
||||||
|
|
@ -430,8 +430,8 @@ class AssetManager {
|
||||||
private loadFallbackAsset(key: string): void {
|
private loadFallbackAsset(key: string): void {
|
||||||
// Load placeholder or default assets
|
// Load placeholder or default assets
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "player":
|
case 'player':
|
||||||
this.scene.load.image("player", "assets/defaults/default-player.png");
|
this.scene.load.image('player', 'assets/defaults/default-player.png');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`No fallback for asset: ${key}`);
|
console.warn(`No fallback for asset: ${key}`);
|
||||||
|
|
@ -458,11 +458,11 @@ class GameSystem {
|
||||||
|
|
||||||
private attemptRecovery(context: string): void {
|
private attemptRecovery(context: string): void {
|
||||||
switch (context) {
|
switch (context) {
|
||||||
case "update":
|
case 'update':
|
||||||
// Reset system state
|
// Reset system state
|
||||||
this.reset();
|
this.reset();
|
||||||
break;
|
break;
|
||||||
case "render":
|
case 'render':
|
||||||
// Disable visual effects
|
// Disable visual effects
|
||||||
this.disableEffects();
|
this.disableEffects();
|
||||||
break;
|
break;
|
||||||
|
|
@ -482,7 +482,7 @@ class GameSystem {
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Example test for game mechanics
|
// Example test for game mechanics
|
||||||
describe("HealthComponent", () => {
|
describe('HealthComponent', () => {
|
||||||
let healthComponent: HealthComponent;
|
let healthComponent: HealthComponent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
@ -490,18 +490,18 @@ describe("HealthComponent", () => {
|
||||||
healthComponent = new HealthComponent(mockEntity, 100);
|
healthComponent = new HealthComponent(mockEntity, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should initialize with correct health", () => {
|
test('should initialize with correct health', () => {
|
||||||
expect(healthComponent.currentHealth).toBe(100);
|
expect(healthComponent.currentHealth).toBe(100);
|
||||||
expect(healthComponent.maxHealth).toBe(100);
|
expect(healthComponent.maxHealth).toBe(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should handle damage correctly", () => {
|
test('should handle damage correctly', () => {
|
||||||
healthComponent.takeDamage(25);
|
healthComponent.takeDamage(25);
|
||||||
expect(healthComponent.currentHealth).toBe(75);
|
expect(healthComponent.currentHealth).toBe(75);
|
||||||
expect(healthComponent.isAlive()).toBe(true);
|
expect(healthComponent.isAlive()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should handle death correctly", () => {
|
test('should handle death correctly', () => {
|
||||||
healthComponent.takeDamage(150);
|
healthComponent.takeDamage(150);
|
||||||
expect(healthComponent.currentHealth).toBe(0);
|
expect(healthComponent.currentHealth).toBe(0);
|
||||||
expect(healthComponent.isAlive()).toBe(false);
|
expect(healthComponent.isAlive()).toBe(false);
|
||||||
|
|
@ -514,7 +514,7 @@ describe("HealthComponent", () => {
|
||||||
**Scene Testing:**
|
**Scene Testing:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
describe("GameScene Integration", () => {
|
describe('GameScene Integration', () => {
|
||||||
let scene: GameScene;
|
let scene: GameScene;
|
||||||
let mockGame: Phaser.Game;
|
let mockGame: Phaser.Game;
|
||||||
|
|
||||||
|
|
@ -524,7 +524,7 @@ describe("GameScene Integration", () => {
|
||||||
scene = new GameScene();
|
scene = new GameScene();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should initialize all systems", () => {
|
test('should initialize all systems', () => {
|
||||||
scene.create({});
|
scene.create({});
|
||||||
|
|
||||||
expect(scene.gameManager).toBeDefined();
|
expect(scene.gameManager).toBeDefined();
|
||||||
|
|
@ -585,25 +585,21 @@ src/
|
||||||
### Story Implementation Process
|
### Story Implementation Process
|
||||||
|
|
||||||
1. **Read Story Requirements:**
|
1. **Read Story Requirements:**
|
||||||
|
|
||||||
- Understand acceptance criteria
|
- Understand acceptance criteria
|
||||||
- Identify technical requirements
|
- Identify technical requirements
|
||||||
- Review performance constraints
|
- Review performance constraints
|
||||||
|
|
||||||
2. **Plan Implementation:**
|
2. **Plan Implementation:**
|
||||||
|
|
||||||
- Identify files to create/modify
|
- Identify files to create/modify
|
||||||
- Consider component architecture
|
- Consider component architecture
|
||||||
- Plan testing approach
|
- Plan testing approach
|
||||||
|
|
||||||
3. **Implement Feature:**
|
3. **Implement Feature:**
|
||||||
|
|
||||||
- Follow TypeScript strict mode
|
- Follow TypeScript strict mode
|
||||||
- Use established patterns
|
- Use established patterns
|
||||||
- Maintain 60 FPS performance
|
- Maintain 60 FPS performance
|
||||||
|
|
||||||
4. **Test Implementation:**
|
4. **Test Implementation:**
|
||||||
|
|
||||||
- Write unit tests for game logic
|
- Write unit tests for game logic
|
||||||
- Test cross-platform functionality
|
- Test cross-platform functionality
|
||||||
- Validate performance targets
|
- Validate performance targets
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
2. If the section contains game flow diagrams, level layouts, or system diagrams, explain each diagram briefly with game development context before offering elicitation options (e.g., "The gameplay loop diagram shows how player actions lead to rewards and progression. Notice how each step maintains player engagement and creates opportunities for skill development.")
|
2. If the section contains game flow diagrams, level layouts, or system diagrams, explain each diagram briefly with game development context before offering elicitation options (e.g., "The gameplay loop diagram shows how player actions lead to rewards and progression. Notice how each step maintains player engagement and creates opportunities for skill development.")
|
||||||
|
|
||||||
3. If the section contains multiple game elements (like multiple mechanics, multiple levels, multiple systems, etc.), inform the user they can apply elicitation actions to:
|
3. If the section contains multiple game elements (like multiple mechanics, multiple levels, multiple systems, etc.), inform the user they can apply elicitation actions to:
|
||||||
|
|
||||||
- The entire section as a whole
|
- The entire section as a whole
|
||||||
- Individual game elements within the section (specify which element when selecting an action)
|
- Individual game elements within the section (specify which element when selecting an action)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
[[LLM: Begin by understanding the game design context and goals. Ask clarifying questions if needed to determine the best approach for game-specific ideation.]]
|
[[LLM: Begin by understanding the game design context and goals. Ask clarifying questions if needed to determine the best approach for game-specific ideation.]]
|
||||||
|
|
||||||
1. **Establish Game Context**
|
1. **Establish Game Context**
|
||||||
|
|
||||||
- Understand the game genre or opportunity area
|
- Understand the game genre or opportunity area
|
||||||
- Identify target audience and platform constraints
|
- Identify target audience and platform constraints
|
||||||
- Determine session goals (concept exploration vs. mechanic refinement)
|
- Determine session goals (concept exploration vs. mechanic refinement)
|
||||||
|
|
@ -27,7 +26,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **"What If" Game Scenarios**
|
1. **"What If" Game Scenarios**
|
||||||
[[LLM: Generate provocative what-if questions that challenge game design assumptions and expand thinking beyond current genre limitations.]]
|
[[LLM: Generate provocative what-if questions that challenge game design assumptions and expand thinking beyond current genre limitations.]]
|
||||||
|
|
||||||
- What if players could rewind time in any genre?
|
- What if players could rewind time in any genre?
|
||||||
- What if the game world reacted to the player's real-world location?
|
- What if the game world reacted to the player's real-world location?
|
||||||
- What if failure was more rewarding than success?
|
- What if failure was more rewarding than success?
|
||||||
|
|
@ -36,7 +34,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Cross-Genre Fusion**
|
2. **Cross-Genre Fusion**
|
||||||
[[LLM: Help user combine unexpected game genres and mechanics to create unique experiences.]]
|
[[LLM: Help user combine unexpected game genres and mechanics to create unique experiences.]]
|
||||||
|
|
||||||
- "How might [genre A] mechanics work in [genre B]?"
|
- "How might [genre A] mechanics work in [genre B]?"
|
||||||
- Puzzle mechanics in action games
|
- Puzzle mechanics in action games
|
||||||
- Dating sim elements in strategy games
|
- Dating sim elements in strategy games
|
||||||
|
|
@ -45,7 +42,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Player Motivation Reversal**
|
3. **Player Motivation Reversal**
|
||||||
[[LLM: Flip traditional player motivations to reveal new gameplay possibilities.]]
|
[[LLM: Flip traditional player motivations to reveal new gameplay possibilities.]]
|
||||||
|
|
||||||
- What if losing was the goal?
|
- What if losing was the goal?
|
||||||
- What if cooperation was forced in competitive games?
|
- What if cooperation was forced in competitive games?
|
||||||
- What if players had to help their enemies?
|
- What if players had to help their enemies?
|
||||||
|
|
@ -62,7 +58,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **SCAMPER for Game Mechanics**
|
1. **SCAMPER for Game Mechanics**
|
||||||
[[LLM: Guide through each SCAMPER prompt specifically for game design.]]
|
[[LLM: Guide through each SCAMPER prompt specifically for game design.]]
|
||||||
|
|
||||||
- **S** = Substitute: What mechanics can be substituted? (walking → flying → swimming)
|
- **S** = Substitute: What mechanics can be substituted? (walking → flying → swimming)
|
||||||
- **C** = Combine: What systems can be merged? (inventory + character growth)
|
- **C** = Combine: What systems can be merged? (inventory + character growth)
|
||||||
- **A** = Adapt: What mechanics from other media? (books, movies, sports)
|
- **A** = Adapt: What mechanics from other media? (books, movies, sports)
|
||||||
|
|
@ -73,7 +68,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Player Agency Spectrum**
|
2. **Player Agency Spectrum**
|
||||||
[[LLM: Explore different levels of player control and agency across game systems.]]
|
[[LLM: Explore different levels of player control and agency across game systems.]]
|
||||||
|
|
||||||
- Full Control: Direct character movement, combat, building
|
- Full Control: Direct character movement, combat, building
|
||||||
- Indirect Control: Setting rules, giving commands, environmental changes
|
- Indirect Control: Setting rules, giving commands, environmental changes
|
||||||
- Influence Only: Suggestions, preferences, emotional reactions
|
- Influence Only: Suggestions, preferences, emotional reactions
|
||||||
|
|
@ -81,7 +75,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Temporal Game Design**
|
3. **Temporal Game Design**
|
||||||
[[LLM: Explore how time affects gameplay and player experience.]]
|
[[LLM: Explore how time affects gameplay and player experience.]]
|
||||||
|
|
||||||
- Real-time vs. turn-based mechanics
|
- Real-time vs. turn-based mechanics
|
||||||
- Time travel and manipulation
|
- Time travel and manipulation
|
||||||
- Persistent vs. session-based progress
|
- Persistent vs. session-based progress
|
||||||
|
|
@ -92,7 +85,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **Emotion-First Design**
|
1. **Emotion-First Design**
|
||||||
[[LLM: Start with target emotions and work backward to mechanics that create them.]]
|
[[LLM: Start with target emotions and work backward to mechanics that create them.]]
|
||||||
|
|
||||||
- Target Emotion: Wonder → Mechanics: Discovery, mystery, scale
|
- Target Emotion: Wonder → Mechanics: Discovery, mystery, scale
|
||||||
- Target Emotion: Triumph → Mechanics: Challenge, skill growth, recognition
|
- Target Emotion: Triumph → Mechanics: Challenge, skill growth, recognition
|
||||||
- Target Emotion: Connection → Mechanics: Cooperation, shared goals, communication
|
- Target Emotion: Connection → Mechanics: Cooperation, shared goals, communication
|
||||||
|
|
@ -100,7 +92,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Player Archetype Brainstorming**
|
2. **Player Archetype Brainstorming**
|
||||||
[[LLM: Design for different player types and motivations.]]
|
[[LLM: Design for different player types and motivations.]]
|
||||||
|
|
||||||
- Achievers: Progression, completion, mastery
|
- Achievers: Progression, completion, mastery
|
||||||
- Explorers: Discovery, secrets, world-building
|
- Explorers: Discovery, secrets, world-building
|
||||||
- Socializers: Interaction, cooperation, community
|
- Socializers: Interaction, cooperation, community
|
||||||
|
|
@ -109,7 +100,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Accessibility-First Innovation**
|
3. **Accessibility-First Innovation**
|
||||||
[[LLM: Generate ideas that make games more accessible while creating new gameplay.]]
|
[[LLM: Generate ideas that make games more accessible while creating new gameplay.]]
|
||||||
|
|
||||||
- Visual impairment considerations leading to audio-focused mechanics
|
- Visual impairment considerations leading to audio-focused mechanics
|
||||||
- Motor accessibility inspiring one-handed or simplified controls
|
- Motor accessibility inspiring one-handed or simplified controls
|
||||||
- Cognitive accessibility driving clear feedback and pacing
|
- Cognitive accessibility driving clear feedback and pacing
|
||||||
|
|
@ -119,7 +109,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **Environmental Storytelling**
|
1. **Environmental Storytelling**
|
||||||
[[LLM: Brainstorm ways the game world itself tells stories without explicit narrative.]]
|
[[LLM: Brainstorm ways the game world itself tells stories without explicit narrative.]]
|
||||||
|
|
||||||
- How does the environment show history?
|
- How does the environment show history?
|
||||||
- What do interactive objects reveal about characters?
|
- What do interactive objects reveal about characters?
|
||||||
- How can level design communicate mood?
|
- How can level design communicate mood?
|
||||||
|
|
@ -127,7 +116,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Player-Generated Narrative**
|
2. **Player-Generated Narrative**
|
||||||
[[LLM: Explore ways players create their own stories through gameplay.]]
|
[[LLM: Explore ways players create their own stories through gameplay.]]
|
||||||
|
|
||||||
- Emergent storytelling through player choices
|
- Emergent storytelling through player choices
|
||||||
- Procedural narrative generation
|
- Procedural narrative generation
|
||||||
- Player-to-player story sharing
|
- Player-to-player story sharing
|
||||||
|
|
@ -135,7 +123,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Genre Expectation Subversion**
|
3. **Genre Expectation Subversion**
|
||||||
[[LLM: Identify and deliberately subvert player expectations within genres.]]
|
[[LLM: Identify and deliberately subvert player expectations within genres.]]
|
||||||
|
|
||||||
- Fantasy RPG where magic is mundane
|
- Fantasy RPG where magic is mundane
|
||||||
- Horror game where monsters are friendly
|
- Horror game where monsters are friendly
|
||||||
- Racing game where going slow is optimal
|
- Racing game where going slow is optimal
|
||||||
|
|
@ -145,7 +132,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **Platform-Specific Design**
|
1. **Platform-Specific Design**
|
||||||
[[LLM: Generate ideas that leverage unique platform capabilities.]]
|
[[LLM: Generate ideas that leverage unique platform capabilities.]]
|
||||||
|
|
||||||
- Mobile: GPS, accelerometer, camera, always-connected
|
- Mobile: GPS, accelerometer, camera, always-connected
|
||||||
- Web: URLs, tabs, social sharing, real-time collaboration
|
- Web: URLs, tabs, social sharing, real-time collaboration
|
||||||
- Console: Controllers, TV viewing, couch co-op
|
- Console: Controllers, TV viewing, couch co-op
|
||||||
|
|
@ -153,7 +139,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Constraint-Based Creativity**
|
2. **Constraint-Based Creativity**
|
||||||
[[LLM: Use technical or design constraints as creative catalysts.]]
|
[[LLM: Use technical or design constraints as creative catalysts.]]
|
||||||
|
|
||||||
- One-button games
|
- One-button games
|
||||||
- Games without graphics
|
- Games without graphics
|
||||||
- Games that play in notification bars
|
- Games that play in notification bars
|
||||||
|
|
@ -199,19 +184,16 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
[[LLM: Guide the brainstorming session with appropriate pacing for game design exploration.]]
|
[[LLM: Guide the brainstorming session with appropriate pacing for game design exploration.]]
|
||||||
|
|
||||||
1. **Inspiration Phase** (10-15 min)
|
1. **Inspiration Phase** (10-15 min)
|
||||||
|
|
||||||
- Reference existing games and mechanics
|
- Reference existing games and mechanics
|
||||||
- Explore player experiences and emotions
|
- Explore player experiences and emotions
|
||||||
- Gather visual and thematic inspiration
|
- Gather visual and thematic inspiration
|
||||||
|
|
||||||
2. **Divergent Exploration** (25-35 min)
|
2. **Divergent Exploration** (25-35 min)
|
||||||
|
|
||||||
- Generate many game concepts or mechanics
|
- Generate many game concepts or mechanics
|
||||||
- Use expansion and fusion techniques
|
- Use expansion and fusion techniques
|
||||||
- Encourage wild and impossible ideas
|
- Encourage wild and impossible ideas
|
||||||
|
|
||||||
3. **Player-Centered Filtering** (15-20 min)
|
3. **Player-Centered Filtering** (15-20 min)
|
||||||
|
|
||||||
- Consider target audience reactions
|
- Consider target audience reactions
|
||||||
- Evaluate emotional impact and engagement
|
- Evaluate emotional impact and engagement
|
||||||
- Group ideas by player experience goals
|
- Group ideas by player experience goals
|
||||||
|
|
|
||||||
|
|
@ -17,21 +17,21 @@ workflow:
|
||||||
- brainstorming_session
|
- brainstorming_session
|
||||||
- game_research_prompt
|
- game_research_prompt
|
||||||
- player_research
|
- player_research
|
||||||
notes: 'Start with brainstorming game concepts, then create comprehensive game brief. SAVE OUTPUT: Copy final game-brief.md to your project''s docs/design/ folder.'
|
notes: "Start with brainstorming game concepts, then create comprehensive game brief. SAVE OUTPUT: Copy final game-brief.md to your project's docs/design/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
creates: game-design-doc.md
|
creates: game-design-doc.md
|
||||||
requires: game-brief.md
|
requires: game-brief.md
|
||||||
optional_steps:
|
optional_steps:
|
||||||
- competitive_analysis
|
- competitive_analysis
|
||||||
- technical_research
|
- technical_research
|
||||||
notes: 'Create detailed Game Design Document using game-design-doc-tmpl. Defines all gameplay mechanics, progression, and technical requirements. SAVE OUTPUT: Copy final game-design-doc.md to your project''s docs/design/ folder.'
|
notes: "Create detailed Game Design Document using game-design-doc-tmpl. Defines all gameplay mechanics, progression, and technical requirements. SAVE OUTPUT: Copy final game-design-doc.md to your project's docs/design/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
creates: level-design-doc.md
|
creates: level-design-doc.md
|
||||||
requires: game-design-doc.md
|
requires: game-design-doc.md
|
||||||
optional_steps:
|
optional_steps:
|
||||||
- level_prototyping
|
- level_prototyping
|
||||||
- difficulty_analysis
|
- difficulty_analysis
|
||||||
notes: 'Create level design framework using level-design-doc-tmpl. Establishes content creation guidelines and performance requirements. SAVE OUTPUT: Copy final level-design-doc.md to your project''s docs/design/ folder.'
|
notes: "Create level design framework using level-design-doc-tmpl. Establishes content creation guidelines and performance requirements. SAVE OUTPUT: Copy final level-design-doc.md to your project's docs/design/ folder."
|
||||||
- agent: solution-architect
|
- agent: solution-architect
|
||||||
creates: game-architecture.md
|
creates: game-architecture.md
|
||||||
requires:
|
requires:
|
||||||
|
|
@ -41,7 +41,7 @@ workflow:
|
||||||
- technical_research_prompt
|
- technical_research_prompt
|
||||||
- performance_analysis
|
- performance_analysis
|
||||||
- platform_research
|
- platform_research
|
||||||
notes: 'Create comprehensive technical architecture using game-architecture-tmpl. Defines Phaser 3 systems, performance optimization, and code structure. SAVE OUTPUT: Copy final game-architecture.md to your project''s docs/architecture/ folder.'
|
notes: "Create comprehensive technical architecture using game-architecture-tmpl. Defines Phaser 3 systems, performance optimization, and code structure. SAVE OUTPUT: Copy final game-architecture.md to your project's docs/architecture/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
validates: design_consistency
|
validates: design_consistency
|
||||||
requires: all_design_documents
|
requires: all_design_documents
|
||||||
|
|
@ -66,7 +66,7 @@ workflow:
|
||||||
optional_steps:
|
optional_steps:
|
||||||
- quick_brainstorming
|
- quick_brainstorming
|
||||||
- concept_validation
|
- concept_validation
|
||||||
notes: 'Create focused game brief for prototype. Emphasize core mechanics and immediate playability. SAVE OUTPUT: Copy final game-brief.md to your project''s docs/ folder.'
|
notes: "Create focused game brief for prototype. Emphasize core mechanics and immediate playability. SAVE OUTPUT: Copy final game-brief.md to your project's docs/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
creates: prototype-design.md
|
creates: prototype-design.md
|
||||||
uses: create-doc prototype-design OR create-game-story
|
uses: create-doc prototype-design OR create-game-story
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ workflow:
|
||||||
notes: Implement stories in priority order. Test frequently and adjust design based on what feels fun. Document discoveries.
|
notes: Implement stories in priority order. Test frequently and adjust design based on what feels fun. Document discoveries.
|
||||||
workflow_end:
|
workflow_end:
|
||||||
action: prototype_evaluation
|
action: prototype_evaluation
|
||||||
notes: 'Prototype complete. Evaluate core mechanics, gather feedback, and decide next steps: iterate, expand, or archive.'
|
notes: "Prototype complete. Evaluate core mechanics, gather feedback, and decide next steps: iterate, expand, or archive."
|
||||||
game_jam_sequence:
|
game_jam_sequence:
|
||||||
- step: jam_concept
|
- step: jam_concept
|
||||||
agent: game-designer
|
agent: game-designer
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,13 @@ commands:
|
||||||
- explain: teach me what and why you did whatever you just did in detail so I can learn. Explain to me as if you were training a junior Unity developer.
|
- explain: teach me what and why you did whatever you just did in detail so I can learn. Explain to me as if you were training a junior Unity developer.
|
||||||
- exit: Say goodbye as the Game Developer, and then abandon inhabiting this persona
|
- exit: Say goodbye as the Game Developer, and then abandon inhabiting this persona
|
||||||
develop-story:
|
develop-story:
|
||||||
order-of-execution: "Read (first or next) task→Implement Task and its subtasks→Write tests→Execute validations→Only if ALL pass, then update the task checkbox with [x]→Update story section File List to ensure it lists and new or modified or deleted source file→repeat order-of-execution until complete"
|
order-of-execution: 'Read (first or next) task→Implement Task and its subtasks→Write tests→Execute validations→Only if ALL pass, then update the task checkbox with [x]→Update story section File List to ensure it lists and new or modified or deleted source file→repeat order-of-execution until complete'
|
||||||
story-file-updates-ONLY:
|
story-file-updates-ONLY:
|
||||||
- CRITICAL: ONLY UPDATE THE STORY FILE WITH UPDATES TO SECTIONS INDICATED BELOW. DO NOT MODIFY ANY OTHER SECTIONS.
|
- CRITICAL: ONLY UPDATE THE STORY FILE WITH UPDATES TO SECTIONS INDICATED BELOW. DO NOT MODIFY ANY OTHER SECTIONS.
|
||||||
- CRITICAL: You are ONLY authorized to edit these specific sections of story files - Tasks / Subtasks Checkboxes, Dev Agent Record section and all its subsections, Agent Model Used, Debug Log References, Completion Notes List, File List, Change Log, Status
|
- CRITICAL: You are ONLY authorized to edit these specific sections of story files - Tasks / Subtasks Checkboxes, Dev Agent Record section and all its subsections, Agent Model Used, Debug Log References, Completion Notes List, File List, Change Log, Status
|
||||||
- CRITICAL: DO NOT modify Status, Story, Acceptance Criteria, Dev Notes, Testing sections, or any other sections not listed above
|
- CRITICAL: DO NOT modify Status, Story, Acceptance Criteria, Dev Notes, Testing sections, or any other sections not listed above
|
||||||
blocking: "HALT for: Unapproved deps needed, confirm with user | Ambiguous after story check | 3 failures attempting to implement or fix something repeatedly | Missing config | Failing regression"
|
blocking: 'HALT for: Unapproved deps needed, confirm with user | Ambiguous after story check | 3 failures attempting to implement or fix something repeatedly | Missing config | Failing regression'
|
||||||
ready-for-review: "Code matches requirements + All validations pass + Follows Unity & C# standards + File List complete + Stable FPS"
|
ready-for-review: 'Code matches requirements + All validations pass + Follows Unity & C# standards + File List complete + Stable FPS'
|
||||||
completion: "All Tasks and Subtasks marked [x] and have tests→Validations and full regression passes (DON'T BE LAZY, EXECUTE ALL TESTS and CONFIRM)→Ensure File List is Complete→run the task execute-checklist for the checklist game-story-dod-checklist→set story status: 'Ready for Review'→HALT"
|
completion: "All Tasks and Subtasks marked [x] and have tests→Validations and full regression passes (DON'T BE LAZY, EXECUTE ALL TESTS and CONFIRM)→Ensure File List is Complete→run the task execute-checklist for the checklist game-story-dod-checklist→set story status: 'Ready for Review'→HALT"
|
||||||
dependencies:
|
dependencies:
|
||||||
tasks:
|
tasks:
|
||||||
|
|
|
||||||
|
|
@ -355,34 +355,29 @@ Ask the user if they want to work through the checklist:
|
||||||
Generate a comprehensive validation report that includes:
|
Generate a comprehensive validation report that includes:
|
||||||
|
|
||||||
1. Executive Summary
|
1. Executive Summary
|
||||||
|
|
||||||
- Overall game architecture readiness (High/Medium/Low)
|
- Overall game architecture readiness (High/Medium/Low)
|
||||||
- Critical risks for game development
|
- Critical risks for game development
|
||||||
- Key strengths of the game architecture
|
- Key strengths of the game architecture
|
||||||
- Unity-specific assessment
|
- Unity-specific assessment
|
||||||
|
|
||||||
2. Game Systems Analysis
|
2. Game Systems Analysis
|
||||||
|
|
||||||
- Pass rate for each major system section
|
- Pass rate for each major system section
|
||||||
- Most concerning gaps in game architecture
|
- Most concerning gaps in game architecture
|
||||||
- Systems requiring immediate attention
|
- Systems requiring immediate attention
|
||||||
- Unity integration completeness
|
- Unity integration completeness
|
||||||
|
|
||||||
3. Performance Risk Assessment
|
3. Performance Risk Assessment
|
||||||
|
|
||||||
- Top 5 performance risks for the game
|
- Top 5 performance risks for the game
|
||||||
- Mobile platform specific concerns
|
- Mobile platform specific concerns
|
||||||
- Frame rate stability risks
|
- Frame rate stability risks
|
||||||
- Memory usage concerns
|
- Memory usage concerns
|
||||||
|
|
||||||
4. Implementation Recommendations
|
4. Implementation Recommendations
|
||||||
|
|
||||||
- Must-fix items before development
|
- Must-fix items before development
|
||||||
- Unity-specific improvements needed
|
- Unity-specific improvements needed
|
||||||
- Game development workflow enhancements
|
- Game development workflow enhancements
|
||||||
|
|
||||||
5. AI Agent Implementation Readiness
|
5. AI Agent Implementation Readiness
|
||||||
|
|
||||||
- Game-specific concerns for AI implementation
|
- Game-specific concerns for AI implementation
|
||||||
- Unity component complexity assessment
|
- Unity component complexity assessment
|
||||||
- Areas needing additional clarification
|
- Areas needing additional clarification
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
1. **Requirements Met:**
|
1. **Requirements Met:**
|
||||||
|
|
||||||
[[LLM: Be specific - list each requirement and whether it's complete. Include game-specific requirements from GDD]]
|
[[LLM: Be specific - list each requirement and whether it's complete. Include game-specific requirements from GDD]]
|
||||||
|
|
||||||
- [ ] All functional requirements specified in the story are implemented.
|
- [ ] All functional requirements specified in the story are implemented.
|
||||||
- [ ] All acceptance criteria defined in the story are met.
|
- [ ] All acceptance criteria defined in the story are met.
|
||||||
- [ ] Game Design Document (GDD) requirements referenced in the story are implemented.
|
- [ ] Game Design Document (GDD) requirements referenced in the story are implemented.
|
||||||
|
|
@ -34,7 +33,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
2. **Coding Standards & Project Structure:**
|
2. **Coding Standards & Project Structure:**
|
||||||
|
|
||||||
[[LLM: Code quality matters for maintainability. Check Unity-specific patterns and C# standards]]
|
[[LLM: Code quality matters for maintainability. Check Unity-specific patterns and C# standards]]
|
||||||
|
|
||||||
- [ ] All new/modified code strictly adheres to `Operational Guidelines`.
|
- [ ] All new/modified code strictly adheres to `Operational Guidelines`.
|
||||||
- [ ] All new/modified code aligns with `Project Structure` (Scripts/, Prefabs/, Scenes/, etc.).
|
- [ ] All new/modified code aligns with `Project Structure` (Scripts/, Prefabs/, Scenes/, etc.).
|
||||||
- [ ] Adherence to `Tech Stack` for Unity version and packages used.
|
- [ ] Adherence to `Tech Stack` for Unity version and packages used.
|
||||||
|
|
@ -48,7 +46,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
3. **Testing:**
|
3. **Testing:**
|
||||||
|
|
||||||
[[LLM: Testing proves your code works. Include Unity-specific testing with NUnit and manual testing]]
|
[[LLM: Testing proves your code works. Include Unity-specific testing with NUnit and manual testing]]
|
||||||
|
|
||||||
- [ ] All required unit tests (NUnit) as per the story and testing strategy are implemented.
|
- [ ] All required unit tests (NUnit) as per the story and testing strategy are implemented.
|
||||||
- [ ] All required integration tests (if applicable) are implemented.
|
- [ ] All required integration tests (if applicable) are implemented.
|
||||||
- [ ] Manual testing performed in Unity Editor for all game functionality.
|
- [ ] Manual testing performed in Unity Editor for all game functionality.
|
||||||
|
|
@ -60,7 +57,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
4. **Functionality & Verification:**
|
4. **Functionality & Verification:**
|
||||||
|
|
||||||
[[LLM: Did you actually run and test your code in Unity? Be specific about game mechanics tested]]
|
[[LLM: Did you actually run and test your code in Unity? Be specific about game mechanics tested]]
|
||||||
|
|
||||||
- [ ] Functionality has been manually verified in Unity Editor and play mode.
|
- [ ] Functionality has been manually verified in Unity Editor and play mode.
|
||||||
- [ ] Game mechanics work as specified in the GDD.
|
- [ ] Game mechanics work as specified in the GDD.
|
||||||
- [ ] Player controls and input handling work correctly.
|
- [ ] Player controls and input handling work correctly.
|
||||||
|
|
@ -73,7 +69,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
5. **Story Administration:**
|
5. **Story Administration:**
|
||||||
|
|
||||||
[[LLM: Documentation helps the next developer. Include Unity-specific implementation notes]]
|
[[LLM: Documentation helps the next developer. Include Unity-specific implementation notes]]
|
||||||
|
|
||||||
- [ ] All tasks within the story file are marked as complete.
|
- [ ] All tasks within the story file are marked as complete.
|
||||||
- [ ] Any clarifications or decisions made during development are documented.
|
- [ ] Any clarifications or decisions made during development are documented.
|
||||||
- [ ] Unity-specific implementation details documented (scene changes, prefab modifications).
|
- [ ] Unity-specific implementation details documented (scene changes, prefab modifications).
|
||||||
|
|
@ -83,7 +78,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
6. **Dependencies, Build & Configuration:**
|
6. **Dependencies, Build & Configuration:**
|
||||||
|
|
||||||
[[LLM: Build issues block everyone. Ensure Unity project builds for all target platforms]]
|
[[LLM: Build issues block everyone. Ensure Unity project builds for all target platforms]]
|
||||||
|
|
||||||
- [ ] Unity project builds successfully without errors.
|
- [ ] Unity project builds successfully without errors.
|
||||||
- [ ] Project builds for all target platforms (desktop/mobile as specified).
|
- [ ] Project builds for all target platforms (desktop/mobile as specified).
|
||||||
- [ ] Any new Unity packages or Asset Store items were pre-approved OR approved by user.
|
- [ ] Any new Unity packages or Asset Store items were pre-approved OR approved by user.
|
||||||
|
|
@ -95,7 +89,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
7. **Game-Specific Quality:**
|
7. **Game-Specific Quality:**
|
||||||
|
|
||||||
[[LLM: Game quality matters. Check performance, game feel, and player experience]]
|
[[LLM: Game quality matters. Check performance, game feel, and player experience]]
|
||||||
|
|
||||||
- [ ] Frame rate meets target (30/60 FPS) on all platforms.
|
- [ ] Frame rate meets target (30/60 FPS) on all platforms.
|
||||||
- [ ] Memory usage within acceptable limits.
|
- [ ] Memory usage within acceptable limits.
|
||||||
- [ ] Game feel and responsiveness meet design requirements.
|
- [ ] Game feel and responsiveness meet design requirements.
|
||||||
|
|
@ -107,7 +100,6 @@ The goal is quality delivery, not just checking boxes.]]
|
||||||
8. **Documentation (If Applicable):**
|
8. **Documentation (If Applicable):**
|
||||||
|
|
||||||
[[LLM: Good documentation prevents future confusion. Include Unity-specific docs]]
|
[[LLM: Good documentation prevents future confusion. Include Unity-specific docs]]
|
||||||
|
|
||||||
- [ ] Code documentation (XML comments) for public APIs complete.
|
- [ ] Code documentation (XML comments) for public APIs complete.
|
||||||
- [ ] Unity component documentation in Inspector updated.
|
- [ ] Unity component documentation in Inspector updated.
|
||||||
- [ ] User-facing documentation updated, if changes impact players.
|
- [ ] User-facing documentation updated, if changes impact players.
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,6 @@ that can handle [specific game requirements] with stable performance."
|
||||||
**Prerequisites**: Game planning documents must exist in `docs/` folder of Unity project
|
**Prerequisites**: Game planning documents must exist in `docs/` folder of Unity project
|
||||||
|
|
||||||
1. **Document Sharding** (CRITICAL STEP for Game Development):
|
1. **Document Sharding** (CRITICAL STEP for Game Development):
|
||||||
|
|
||||||
- Documents created by Game Designer/Architect (in Web or IDE) MUST be sharded for development
|
- Documents created by Game Designer/Architect (in Web or IDE) MUST be sharded for development
|
||||||
- Use core BMad agents or tools to shard:
|
- Use core BMad agents or tools to shard:
|
||||||
a) **Manual**: Use core BMad `shard-doc` task if available
|
a) **Manual**: Use core BMad `shard-doc` task if available
|
||||||
|
|
@ -293,20 +292,17 @@ Resulting Unity Project Folder Structure:
|
||||||
3. **Game Development Cycle** (Sequential, one game story at a time):
|
3. **Game Development Cycle** (Sequential, one game story at a time):
|
||||||
|
|
||||||
**CRITICAL CONTEXT MANAGEMENT for Unity Development**:
|
**CRITICAL CONTEXT MANAGEMENT for Unity Development**:
|
||||||
|
|
||||||
- **Context windows matter!** Always use fresh, clean context windows
|
- **Context windows matter!** Always use fresh, clean context windows
|
||||||
- **Model selection matters!** Use most powerful thinking model for Game SM story creation
|
- **Model selection matters!** Use most powerful thinking model for Game SM story creation
|
||||||
- **ALWAYS start new chat between Game SM, Game Dev, and QA work**
|
- **ALWAYS start new chat between Game SM, Game Dev, and QA work**
|
||||||
|
|
||||||
**Step 1 - Game Story Creation**:
|
**Step 1 - Game Story Creation**:
|
||||||
|
|
||||||
- **NEW CLEAN CHAT** → Select powerful model → `/bmad2du/game-sm` → `*draft`
|
- **NEW CLEAN CHAT** → Select powerful model → `/bmad2du/game-sm` → `*draft`
|
||||||
- Game SM executes create-game-story task using `game-story-tmpl`
|
- Game SM executes create-game-story task using `game-story-tmpl`
|
||||||
- Review generated story in `docs/game-stories/`
|
- Review generated story in `docs/game-stories/`
|
||||||
- Update status from "Draft" to "Approved"
|
- Update status from "Draft" to "Approved"
|
||||||
|
|
||||||
**Step 2 - Unity Game Story Implementation**:
|
**Step 2 - Unity Game Story Implementation**:
|
||||||
|
|
||||||
- **NEW CLEAN CHAT** → `/bmad2du/game-developer`
|
- **NEW CLEAN CHAT** → `/bmad2du/game-developer`
|
||||||
- Agent asks which game story to implement
|
- Agent asks which game story to implement
|
||||||
- Include story file content to save game dev agent lookup time
|
- Include story file content to save game dev agent lookup time
|
||||||
|
|
@ -315,7 +311,6 @@ Resulting Unity Project Folder Structure:
|
||||||
- Game Dev marks story as "Review" when complete with all Unity tests passing
|
- Game Dev marks story as "Review" when complete with all Unity tests passing
|
||||||
|
|
||||||
**Step 3 - Game QA Review**:
|
**Step 3 - Game QA Review**:
|
||||||
|
|
||||||
- **NEW CLEAN CHAT** → Use core `@qa` agent → execute review-story task
|
- **NEW CLEAN CHAT** → Use core `@qa` agent → execute review-story task
|
||||||
- QA performs senior Unity developer code review
|
- QA performs senior Unity developer code review
|
||||||
- QA can refactor and improve Unity code directly
|
- QA can refactor and improve Unity code directly
|
||||||
|
|
@ -355,14 +350,12 @@ Since this expansion pack doesn't include specific brownfield templates, you'll
|
||||||
|
|
||||||
1. **Upload Unity project to Web UI** (GitHub URL, files, or zip)
|
1. **Upload Unity project to Web UI** (GitHub URL, files, or zip)
|
||||||
2. **Create adapted Game Design Document**: `/bmad2du/game-designer` - Modify `game-design-doc-tmpl` to include:
|
2. **Create adapted Game Design Document**: `/bmad2du/game-designer` - Modify `game-design-doc-tmpl` to include:
|
||||||
|
|
||||||
- Analysis of existing game systems
|
- Analysis of existing game systems
|
||||||
- Integration points for new features
|
- Integration points for new features
|
||||||
- Compatibility requirements
|
- Compatibility requirements
|
||||||
- Risk assessment for changes
|
- Risk assessment for changes
|
||||||
|
|
||||||
3. **Game Architecture Planning**:
|
3. **Game Architecture Planning**:
|
||||||
|
|
||||||
- Use `/bmad2du/game-architect` with `game-architecture-tmpl`
|
- Use `/bmad2du/game-architect` with `game-architecture-tmpl`
|
||||||
- Focus on how new features integrate with existing Unity systems
|
- Focus on how new features integrate with existing Unity systems
|
||||||
- Plan for gradual rollout and testing
|
- Plan for gradual rollout and testing
|
||||||
|
|
@ -463,7 +456,7 @@ Use the `shard-doc` task or `@kayvan/markdown-tree-parser` tool for automatic ga
|
||||||
|
|
||||||
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
- **Claude Code**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Cursor**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Windsurf**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Windsurf**: `/bmad2du/game-designer`, `/bmad2du/game-developer`, `/bmad2du/game-sm`, `/bmad2du/game-architect`
|
||||||
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
- **Trae**: `@bmad2du/game-designer`, `@bmad2du/game-developer`, `@bmad2du/game-sm`, `@bmad2du/game-architect`
|
||||||
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
- **Roo Code**: Select mode from mode selector with bmad2du prefix
|
||||||
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
- **GitHub Copilot**: Open the Chat view (`⌃⌘I` on Mac, `Ctrl+Alt+I` on Windows/Linux) and select the appropriate game agent.
|
||||||
|
|
|
||||||
|
|
@ -531,25 +531,21 @@ Assets/
|
||||||
### Story Implementation Process
|
### Story Implementation Process
|
||||||
|
|
||||||
1. **Read Story Requirements:**
|
1. **Read Story Requirements:**
|
||||||
|
|
||||||
- Understand acceptance criteria
|
- Understand acceptance criteria
|
||||||
- Identify technical requirements
|
- Identify technical requirements
|
||||||
- Review performance constraints
|
- Review performance constraints
|
||||||
|
|
||||||
2. **Plan Implementation:**
|
2. **Plan Implementation:**
|
||||||
|
|
||||||
- Identify files to create/modify
|
- Identify files to create/modify
|
||||||
- Consider Unity's component-based architecture
|
- Consider Unity's component-based architecture
|
||||||
- Plan testing approach
|
- Plan testing approach
|
||||||
|
|
||||||
3. **Implement Feature:**
|
3. **Implement Feature:**
|
||||||
|
|
||||||
- Write clean C# code following all guidelines
|
- Write clean C# code following all guidelines
|
||||||
- Use established patterns
|
- Use established patterns
|
||||||
- Maintain stable FPS performance
|
- Maintain stable FPS performance
|
||||||
|
|
||||||
4. **Test Implementation:**
|
4. **Test Implementation:**
|
||||||
|
|
||||||
- Write edit mode tests for game logic
|
- Write edit mode tests for game logic
|
||||||
- Write play mode tests for integration testing
|
- Write play mode tests for integration testing
|
||||||
- Test cross-platform functionality
|
- Test cross-platform functionality
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
2. If the section contains game flow diagrams, level layouts, or system diagrams, explain each diagram briefly with game development context before offering elicitation options (e.g., "The gameplay loop diagram shows how player actions lead to rewards and progression. Notice how each step maintains player engagement and creates opportunities for skill development.")
|
2. If the section contains game flow diagrams, level layouts, or system diagrams, explain each diagram briefly with game development context before offering elicitation options (e.g., "The gameplay loop diagram shows how player actions lead to rewards and progression. Notice how each step maintains player engagement and creates opportunities for skill development.")
|
||||||
|
|
||||||
3. If the section contains multiple game elements (like multiple mechanics, multiple levels, multiple systems, etc.), inform the user they can apply elicitation actions to:
|
3. If the section contains multiple game elements (like multiple mechanics, multiple levels, multiple systems, etc.), inform the user they can apply elicitation actions to:
|
||||||
|
|
||||||
- The entire section as a whole
|
- The entire section as a whole
|
||||||
- Individual game elements within the section (specify which element when selecting an action)
|
- Individual game elements within the section (specify which element when selecting an action)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
### 1. Initial Setup & Mode Selection
|
### 1. Initial Setup & Mode Selection
|
||||||
|
|
||||||
- **Acknowledge Task & Inputs:**
|
- **Acknowledge Task & Inputs:**
|
||||||
|
|
||||||
- Confirm with the user that the "Game Development Correct Course Task" is being initiated.
|
- Confirm with the user that the "Game Development Correct Course Task" is being initiated.
|
||||||
- Verify the change trigger (e.g., performance issue, platform constraint, gameplay feedback, technical blocker).
|
- Verify the change trigger (e.g., performance issue, platform constraint, gameplay feedback, technical blocker).
|
||||||
- Confirm access to relevant game artifacts:
|
- Confirm access to relevant game artifacts:
|
||||||
|
|
@ -35,7 +34,6 @@
|
||||||
### 2. Execute Game Development Checklist Analysis
|
### 2. Execute Game Development Checklist Analysis
|
||||||
|
|
||||||
- Systematically work through the game-change-checklist sections:
|
- Systematically work through the game-change-checklist sections:
|
||||||
|
|
||||||
1. **Change Context & Game Impact**
|
1. **Change Context & Game Impact**
|
||||||
2. **Feature/System Impact Analysis**
|
2. **Feature/System Impact Analysis**
|
||||||
3. **Technical Artifact Conflict Resolution**
|
3. **Technical Artifact Conflict Resolution**
|
||||||
|
|
@ -60,7 +58,6 @@
|
||||||
Based on the analysis and agreed path forward:
|
Based on the analysis and agreed path forward:
|
||||||
|
|
||||||
- **Identify affected game artifacts requiring updates:**
|
- **Identify affected game artifacts requiring updates:**
|
||||||
|
|
||||||
- GDD sections (mechanics, systems, progression)
|
- GDD sections (mechanics, systems, progression)
|
||||||
- Technical specifications (architecture, performance targets)
|
- Technical specifications (architecture, performance targets)
|
||||||
- Unity-specific configurations (build settings, quality settings)
|
- Unity-specific configurations (build settings, quality settings)
|
||||||
|
|
@ -69,7 +66,6 @@ Based on the analysis and agreed path forward:
|
||||||
- Platform-specific adaptations
|
- Platform-specific adaptations
|
||||||
|
|
||||||
- **Draft explicit changes for each artifact:**
|
- **Draft explicit changes for each artifact:**
|
||||||
|
|
||||||
- **Game Stories:** Revise story text, Unity-specific acceptance criteria, technical constraints
|
- **Game Stories:** Revise story text, Unity-specific acceptance criteria, technical constraints
|
||||||
- **Technical Specs:** Update architecture diagrams, component hierarchies, performance budgets
|
- **Technical Specs:** Update architecture diagrams, component hierarchies, performance budgets
|
||||||
- **Unity Configurations:** Propose settings changes, optimization strategies, platform variants
|
- **Unity Configurations:** Propose settings changes, optimization strategies, platform variants
|
||||||
|
|
@ -89,14 +85,12 @@ Based on the analysis and agreed path forward:
|
||||||
- Create a comprehensive proposal document containing:
|
- Create a comprehensive proposal document containing:
|
||||||
|
|
||||||
**A. Change Summary:**
|
**A. Change Summary:**
|
||||||
|
|
||||||
- Original issue (performance, gameplay, technical constraint)
|
- Original issue (performance, gameplay, technical constraint)
|
||||||
- Game systems affected
|
- Game systems affected
|
||||||
- Platform/performance implications
|
- Platform/performance implications
|
||||||
- Chosen solution approach
|
- Chosen solution approach
|
||||||
|
|
||||||
**B. Technical Impact Analysis:**
|
**B. Technical Impact Analysis:**
|
||||||
|
|
||||||
- Unity architecture changes needed
|
- Unity architecture changes needed
|
||||||
- Performance implications (with metrics)
|
- Performance implications (with metrics)
|
||||||
- Platform compatibility effects
|
- Platform compatibility effects
|
||||||
|
|
@ -104,14 +98,12 @@ Based on the analysis and agreed path forward:
|
||||||
- Third-party dependency impacts
|
- Third-party dependency impacts
|
||||||
|
|
||||||
**C. Specific Proposed Edits:**
|
**C. Specific Proposed Edits:**
|
||||||
|
|
||||||
- For each game story: "Change Story GS-X.Y from: [old] To: [new]"
|
- For each game story: "Change Story GS-X.Y from: [old] To: [new]"
|
||||||
- For technical specs: "Update Unity Architecture Section X: [changes]"
|
- For technical specs: "Update Unity Architecture Section X: [changes]"
|
||||||
- For GDD: "Modify [Feature] in Section Y: [updates]"
|
- For GDD: "Modify [Feature] in Section Y: [updates]"
|
||||||
- For configurations: "Change [Setting] from [old_value] to [new_value]"
|
- For configurations: "Change [Setting] from [old_value] to [new_value]"
|
||||||
|
|
||||||
**D. Implementation Considerations:**
|
**D. Implementation Considerations:**
|
||||||
|
|
||||||
- Required Unity version updates
|
- Required Unity version updates
|
||||||
- Asset reimport needs
|
- Asset reimport needs
|
||||||
- Shader recompilation requirements
|
- Shader recompilation requirements
|
||||||
|
|
@ -123,7 +115,6 @@ Based on the analysis and agreed path forward:
|
||||||
- Provide the finalized document to the user
|
- Provide the finalized document to the user
|
||||||
|
|
||||||
- **Based on change scope:**
|
- **Based on change scope:**
|
||||||
|
|
||||||
- **Minor adjustments (can be handled in current sprint):**
|
- **Minor adjustments (can be handled in current sprint):**
|
||||||
- Confirm task completion
|
- Confirm task completion
|
||||||
- Suggest handoff to game-dev agent for implementation
|
- Suggest handoff to game-dev agent for implementation
|
||||||
|
|
@ -137,7 +128,6 @@ Based on the analysis and agreed path forward:
|
||||||
## Output Deliverables
|
## Output Deliverables
|
||||||
|
|
||||||
- **Primary:** "Game Development Change Proposal" document containing:
|
- **Primary:** "Game Development Change Proposal" document containing:
|
||||||
|
|
||||||
- Game-specific change analysis
|
- Game-specific change analysis
|
||||||
- Technical impact assessment with Unity context
|
- Technical impact assessment with Unity context
|
||||||
- Platform and performance considerations
|
- Platform and performance considerations
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
[[LLM: Begin by understanding the game design context and goals. Ask clarifying questions if needed to determine the best approach for game-specific ideation.]]
|
[[LLM: Begin by understanding the game design context and goals. Ask clarifying questions if needed to determine the best approach for game-specific ideation.]]
|
||||||
|
|
||||||
1. **Establish Game Context**
|
1. **Establish Game Context**
|
||||||
|
|
||||||
- Understand the game genre or opportunity area
|
- Understand the game genre or opportunity area
|
||||||
- Identify target audience and platform constraints
|
- Identify target audience and platform constraints
|
||||||
- Determine session goals (concept exploration vs. mechanic refinement)
|
- Determine session goals (concept exploration vs. mechanic refinement)
|
||||||
|
|
@ -27,7 +26,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **"What If" Game Scenarios**
|
1. **"What If" Game Scenarios**
|
||||||
[[LLM: Generate provocative what-if questions that challenge game design assumptions and expand thinking beyond current genre limitations.]]
|
[[LLM: Generate provocative what-if questions that challenge game design assumptions and expand thinking beyond current genre limitations.]]
|
||||||
|
|
||||||
- What if players could rewind time in any genre?
|
- What if players could rewind time in any genre?
|
||||||
- What if the game world reacted to the player's real-world location?
|
- What if the game world reacted to the player's real-world location?
|
||||||
- What if failure was more rewarding than success?
|
- What if failure was more rewarding than success?
|
||||||
|
|
@ -36,7 +34,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Cross-Genre Fusion**
|
2. **Cross-Genre Fusion**
|
||||||
[[LLM: Help user combine unexpected game genres and mechanics to create unique experiences.]]
|
[[LLM: Help user combine unexpected game genres and mechanics to create unique experiences.]]
|
||||||
|
|
||||||
- "How might [genre A] mechanics work in [genre B]?"
|
- "How might [genre A] mechanics work in [genre B]?"
|
||||||
- Puzzle mechanics in action games
|
- Puzzle mechanics in action games
|
||||||
- Dating sim elements in strategy games
|
- Dating sim elements in strategy games
|
||||||
|
|
@ -45,7 +42,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Player Motivation Reversal**
|
3. **Player Motivation Reversal**
|
||||||
[[LLM: Flip traditional player motivations to reveal new gameplay possibilities.]]
|
[[LLM: Flip traditional player motivations to reveal new gameplay possibilities.]]
|
||||||
|
|
||||||
- What if losing was the goal?
|
- What if losing was the goal?
|
||||||
- What if cooperation was forced in competitive games?
|
- What if cooperation was forced in competitive games?
|
||||||
- What if players had to help their enemies?
|
- What if players had to help their enemies?
|
||||||
|
|
@ -62,7 +58,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **SCAMPER for Game Mechanics**
|
1. **SCAMPER for Game Mechanics**
|
||||||
[[LLM: Guide through each SCAMPER prompt specifically for game design.]]
|
[[LLM: Guide through each SCAMPER prompt specifically for game design.]]
|
||||||
|
|
||||||
- **S** = Substitute: What mechanics can be substituted? (walking → flying → swimming)
|
- **S** = Substitute: What mechanics can be substituted? (walking → flying → swimming)
|
||||||
- **C** = Combine: What systems can be merged? (inventory + character growth)
|
- **C** = Combine: What systems can be merged? (inventory + character growth)
|
||||||
- **A** = Adapt: What mechanics from other media? (books, movies, sports)
|
- **A** = Adapt: What mechanics from other media? (books, movies, sports)
|
||||||
|
|
@ -73,7 +68,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Player Agency Spectrum**
|
2. **Player Agency Spectrum**
|
||||||
[[LLM: Explore different levels of player control and agency across game systems.]]
|
[[LLM: Explore different levels of player control and agency across game systems.]]
|
||||||
|
|
||||||
- Full Control: Direct character movement, combat, building
|
- Full Control: Direct character movement, combat, building
|
||||||
- Indirect Control: Setting rules, giving commands, environmental changes
|
- Indirect Control: Setting rules, giving commands, environmental changes
|
||||||
- Influence Only: Suggestions, preferences, emotional reactions
|
- Influence Only: Suggestions, preferences, emotional reactions
|
||||||
|
|
@ -81,7 +75,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Temporal Game Design**
|
3. **Temporal Game Design**
|
||||||
[[LLM: Explore how time affects gameplay and player experience.]]
|
[[LLM: Explore how time affects gameplay and player experience.]]
|
||||||
|
|
||||||
- Real-time vs. turn-based mechanics
|
- Real-time vs. turn-based mechanics
|
||||||
- Time travel and manipulation
|
- Time travel and manipulation
|
||||||
- Persistent vs. session-based progress
|
- Persistent vs. session-based progress
|
||||||
|
|
@ -92,7 +85,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **Emotion-First Design**
|
1. **Emotion-First Design**
|
||||||
[[LLM: Start with target emotions and work backward to mechanics that create them.]]
|
[[LLM: Start with target emotions and work backward to mechanics that create them.]]
|
||||||
|
|
||||||
- Target Emotion: Wonder → Mechanics: Discovery, mystery, scale
|
- Target Emotion: Wonder → Mechanics: Discovery, mystery, scale
|
||||||
- Target Emotion: Triumph → Mechanics: Challenge, skill growth, recognition
|
- Target Emotion: Triumph → Mechanics: Challenge, skill growth, recognition
|
||||||
- Target Emotion: Connection → Mechanics: Cooperation, shared goals, communication
|
- Target Emotion: Connection → Mechanics: Cooperation, shared goals, communication
|
||||||
|
|
@ -100,7 +92,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Player Archetype Brainstorming**
|
2. **Player Archetype Brainstorming**
|
||||||
[[LLM: Design for different player types and motivations.]]
|
[[LLM: Design for different player types and motivations.]]
|
||||||
|
|
||||||
- Achievers: Progression, completion, mastery
|
- Achievers: Progression, completion, mastery
|
||||||
- Explorers: Discovery, secrets, world-building
|
- Explorers: Discovery, secrets, world-building
|
||||||
- Socializers: Interaction, cooperation, community
|
- Socializers: Interaction, cooperation, community
|
||||||
|
|
@ -109,7 +100,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Accessibility-First Innovation**
|
3. **Accessibility-First Innovation**
|
||||||
[[LLM: Generate ideas that make games more accessible while creating new gameplay.]]
|
[[LLM: Generate ideas that make games more accessible while creating new gameplay.]]
|
||||||
|
|
||||||
- Visual impairment considerations leading to audio-focused mechanics
|
- Visual impairment considerations leading to audio-focused mechanics
|
||||||
- Motor accessibility inspiring one-handed or simplified controls
|
- Motor accessibility inspiring one-handed or simplified controls
|
||||||
- Cognitive accessibility driving clear feedback and pacing
|
- Cognitive accessibility driving clear feedback and pacing
|
||||||
|
|
@ -119,7 +109,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **Environmental Storytelling**
|
1. **Environmental Storytelling**
|
||||||
[[LLM: Brainstorm ways the game world itself tells stories without explicit narrative.]]
|
[[LLM: Brainstorm ways the game world itself tells stories without explicit narrative.]]
|
||||||
|
|
||||||
- How does the environment show history?
|
- How does the environment show history?
|
||||||
- What do interactive objects reveal about characters?
|
- What do interactive objects reveal about characters?
|
||||||
- How can level design communicate mood?
|
- How can level design communicate mood?
|
||||||
|
|
@ -127,7 +116,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Player-Generated Narrative**
|
2. **Player-Generated Narrative**
|
||||||
[[LLM: Explore ways players create their own stories through gameplay.]]
|
[[LLM: Explore ways players create their own stories through gameplay.]]
|
||||||
|
|
||||||
- Emergent storytelling through player choices
|
- Emergent storytelling through player choices
|
||||||
- Procedural narrative generation
|
- Procedural narrative generation
|
||||||
- Player-to-player story sharing
|
- Player-to-player story sharing
|
||||||
|
|
@ -135,7 +123,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
3. **Genre Expectation Subversion**
|
3. **Genre Expectation Subversion**
|
||||||
[[LLM: Identify and deliberately subvert player expectations within genres.]]
|
[[LLM: Identify and deliberately subvert player expectations within genres.]]
|
||||||
|
|
||||||
- Fantasy RPG where magic is mundane
|
- Fantasy RPG where magic is mundane
|
||||||
- Horror game where monsters are friendly
|
- Horror game where monsters are friendly
|
||||||
- Racing game where going slow is optimal
|
- Racing game where going slow is optimal
|
||||||
|
|
@ -145,7 +132,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
1. **Platform-Specific Design**
|
1. **Platform-Specific Design**
|
||||||
[[LLM: Generate ideas that leverage unique platform capabilities.]]
|
[[LLM: Generate ideas that leverage unique platform capabilities.]]
|
||||||
|
|
||||||
- Mobile: GPS, accelerometer, camera, always-connected
|
- Mobile: GPS, accelerometer, camera, always-connected
|
||||||
- Web: URLs, tabs, social sharing, real-time collaboration
|
- Web: URLs, tabs, social sharing, real-time collaboration
|
||||||
- Console: Controllers, TV viewing, couch co-op
|
- Console: Controllers, TV viewing, couch co-op
|
||||||
|
|
@ -153,7 +139,6 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
|
|
||||||
2. **Constraint-Based Creativity**
|
2. **Constraint-Based Creativity**
|
||||||
[[LLM: Use technical or design constraints as creative catalysts.]]
|
[[LLM: Use technical or design constraints as creative catalysts.]]
|
||||||
|
|
||||||
- One-button games
|
- One-button games
|
||||||
- Games without graphics
|
- Games without graphics
|
||||||
- Games that play in notification bars
|
- Games that play in notification bars
|
||||||
|
|
@ -199,19 +184,16 @@ This task provides a comprehensive toolkit of creative brainstorming techniques
|
||||||
[[LLM: Guide the brainstorming session with appropriate pacing for game design exploration.]]
|
[[LLM: Guide the brainstorming session with appropriate pacing for game design exploration.]]
|
||||||
|
|
||||||
1. **Inspiration Phase** (10-15 min)
|
1. **Inspiration Phase** (10-15 min)
|
||||||
|
|
||||||
- Reference existing games and mechanics
|
- Reference existing games and mechanics
|
||||||
- Explore player experiences and emotions
|
- Explore player experiences and emotions
|
||||||
- Gather visual and thematic inspiration
|
- Gather visual and thematic inspiration
|
||||||
|
|
||||||
2. **Divergent Exploration** (25-35 min)
|
2. **Divergent Exploration** (25-35 min)
|
||||||
|
|
||||||
- Generate many game concepts or mechanics
|
- Generate many game concepts or mechanics
|
||||||
- Use expansion and fusion techniques
|
- Use expansion and fusion techniques
|
||||||
- Encourage wild and impossible ideas
|
- Encourage wild and impossible ideas
|
||||||
|
|
||||||
3. **Player-Centered Filtering** (15-20 min)
|
3. **Player-Centered Filtering** (15-20 min)
|
||||||
|
|
||||||
- Consider target audience reactions
|
- Consider target audience reactions
|
||||||
- Evaluate emotional impact and engagement
|
- Evaluate emotional impact and engagement
|
||||||
- Group ideas by player experience goals
|
- Group ideas by player experience goals
|
||||||
|
|
|
||||||
|
|
@ -17,21 +17,21 @@ workflow:
|
||||||
- brainstorming_session
|
- brainstorming_session
|
||||||
- game_research_prompt
|
- game_research_prompt
|
||||||
- player_research
|
- player_research
|
||||||
notes: 'Start with brainstorming game concepts, then create comprehensive game brief. SAVE OUTPUT: Copy final game-brief.md to your project''s docs/design/ folder.'
|
notes: "Start with brainstorming game concepts, then create comprehensive game brief. SAVE OUTPUT: Copy final game-brief.md to your project's docs/design/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
creates: game-design-doc.md
|
creates: game-design-doc.md
|
||||||
requires: game-brief.md
|
requires: game-brief.md
|
||||||
optional_steps:
|
optional_steps:
|
||||||
- competitive_analysis
|
- competitive_analysis
|
||||||
- technical_research
|
- technical_research
|
||||||
notes: 'Create detailed Game Design Document using game-design-doc-tmpl. Defines all gameplay mechanics, progression, and technical requirements. SAVE OUTPUT: Copy final game-design-doc.md to your project''s docs/design/ folder.'
|
notes: "Create detailed Game Design Document using game-design-doc-tmpl. Defines all gameplay mechanics, progression, and technical requirements. SAVE OUTPUT: Copy final game-design-doc.md to your project's docs/design/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
creates: level-design-doc.md
|
creates: level-design-doc.md
|
||||||
requires: game-design-doc.md
|
requires: game-design-doc.md
|
||||||
optional_steps:
|
optional_steps:
|
||||||
- level_prototyping
|
- level_prototyping
|
||||||
- difficulty_analysis
|
- difficulty_analysis
|
||||||
notes: 'Create level design framework using level-design-doc-tmpl. Establishes content creation guidelines and performance requirements. SAVE OUTPUT: Copy final level-design-doc.md to your project''s docs/design/ folder.'
|
notes: "Create level design framework using level-design-doc-tmpl. Establishes content creation guidelines and performance requirements. SAVE OUTPUT: Copy final level-design-doc.md to your project's docs/design/ folder."
|
||||||
- agent: solution-architect
|
- agent: solution-architect
|
||||||
creates: game-architecture.md
|
creates: game-architecture.md
|
||||||
requires:
|
requires:
|
||||||
|
|
@ -41,7 +41,7 @@ workflow:
|
||||||
- technical_research_prompt
|
- technical_research_prompt
|
||||||
- performance_analysis
|
- performance_analysis
|
||||||
- platform_research
|
- platform_research
|
||||||
notes: 'Create comprehensive technical architecture using game-architecture-tmpl. Defines Unity systems, performance optimization, and code structure. SAVE OUTPUT: Copy final game-architecture.md to your project''s docs/architecture/ folder.'
|
notes: "Create comprehensive technical architecture using game-architecture-tmpl. Defines Unity systems, performance optimization, and code structure. SAVE OUTPUT: Copy final game-architecture.md to your project's docs/architecture/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
validates: design_consistency
|
validates: design_consistency
|
||||||
requires: all_design_documents
|
requires: all_design_documents
|
||||||
|
|
@ -66,7 +66,7 @@ workflow:
|
||||||
optional_steps:
|
optional_steps:
|
||||||
- quick_brainstorming
|
- quick_brainstorming
|
||||||
- concept_validation
|
- concept_validation
|
||||||
notes: 'Create focused game brief for prototype. Emphasize core mechanics and immediate playability. SAVE OUTPUT: Copy final game-brief.md to your project''s docs/ folder.'
|
notes: "Create focused game brief for prototype. Emphasize core mechanics and immediate playability. SAVE OUTPUT: Copy final game-brief.md to your project's docs/ folder."
|
||||||
- agent: game-designer
|
- agent: game-designer
|
||||||
creates: prototype-design.md
|
creates: prototype-design.md
|
||||||
uses: create-doc prototype-design OR create-game-story
|
uses: create-doc prototype-design OR create-game-story
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ workflow:
|
||||||
notes: Implement stories in priority order. Test frequently in the Unity Editor and adjust design based on what feels fun. Document discoveries.
|
notes: Implement stories in priority order. Test frequently in the Unity Editor and adjust design based on what feels fun. Document discoveries.
|
||||||
workflow_end:
|
workflow_end:
|
||||||
action: prototype_evaluation
|
action: prototype_evaluation
|
||||||
notes: 'Prototype complete. Evaluate core mechanics, gather feedback, and decide next steps: iterate, expand, or archive.'
|
notes: "Prototype complete. Evaluate core mechanics, gather feedback, and decide next steps: iterate, expand, or archive."
|
||||||
game_jam_sequence:
|
game_jam_sequence:
|
||||||
- step: jam_concept
|
- step: jam_concept
|
||||||
agent: game-designer
|
agent: game-designer
|
||||||
|
|
|
||||||
|
|
@ -247,17 +247,14 @@ A comprehensive 16-section checklist covering:
|
||||||
### Common Issues
|
### Common Issues
|
||||||
|
|
||||||
1. **Infrastructure Drift**
|
1. **Infrastructure Drift**
|
||||||
|
|
||||||
- Solution: Implement drift detection in IaC pipelines
|
- Solution: Implement drift detection in IaC pipelines
|
||||||
- Prevention: Restrict manual changes, enforce GitOps
|
- Prevention: Restrict manual changes, enforce GitOps
|
||||||
|
|
||||||
2. **Cost Overruns**
|
2. **Cost Overruns**
|
||||||
|
|
||||||
- Solution: Implement cost monitoring and alerts
|
- Solution: Implement cost monitoring and alerts
|
||||||
- Prevention: Resource tagging, budget limits
|
- Prevention: Resource tagging, budget limits
|
||||||
|
|
||||||
3. **Performance Problems**
|
3. **Performance Problems**
|
||||||
|
|
||||||
- Solution: Review monitoring data, scale resources
|
- Solution: Review monitoring data, scale resources
|
||||||
- Prevention: Load testing, capacity planning
|
- Prevention: Load testing, capacity planning
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ To conduct a thorough review of existing infrastructure to identify improvement
|
||||||
### 3. Conduct Systematic Review
|
### 3. Conduct Systematic Review
|
||||||
|
|
||||||
- **If "Incremental Mode" was selected:**
|
- **If "Incremental Mode" was selected:**
|
||||||
|
|
||||||
- For each section of the infrastructure checklist:
|
- For each section of the infrastructure checklist:
|
||||||
- **a. Present Section Focus:** Explain what aspects of infrastructure this section reviews
|
- **a. Present Section Focus:** Explain what aspects of infrastructure this section reviews
|
||||||
- **b. Work Through Items:** Examine each checklist item against current infrastructure
|
- **b. Work Through Items:** Examine each checklist item against current infrastructure
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ To comprehensively validate platform infrastructure changes against security, re
|
||||||
### 4. Execute Comprehensive Platform Validation Process
|
### 4. Execute Comprehensive Platform Validation Process
|
||||||
|
|
||||||
- **If "Incremental Mode" was selected:**
|
- **If "Incremental Mode" was selected:**
|
||||||
|
|
||||||
- For each section of the infrastructure checklist (Sections 1-16):
|
- For each section of the infrastructure checklist (Sections 1-16):
|
||||||
- **a. Present Section Purpose:** Explain what this section validates and why it's important for platform operations
|
- **a. Present Section Purpose:** Explain what this section validates and why it's important for platform operations
|
||||||
- **b. Work Through Items:** Present each checklist item, guide the user through validation, and document compliance or gaps
|
- **b. Work Through Items:** Present each checklist item, guide the user through validation, and document compliance or gaps
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
98
package.json
98
package.json
|
|
@ -1,7 +1,23 @@
|
||||||
{
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "4.36.2",
|
"version": "4.36.2",
|
||||||
"description": "Breakthrough Method of Agile AI-driven Development",
|
"description": "Breakthrough Method of Agile AI-driven Development",
|
||||||
|
"keywords": [
|
||||||
|
"agile",
|
||||||
|
"ai",
|
||||||
|
"orchestrator",
|
||||||
|
"development",
|
||||||
|
"methodology",
|
||||||
|
"agents",
|
||||||
|
"bmad"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/bmadcode/BMAD-METHOD.git"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "Brian (BMad) Madison",
|
||||||
"main": "tools/cli.js",
|
"main": "tools/cli.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"bmad": "tools/bmad-npx-wrapper.js",
|
"bmad": "tools/bmad-npx-wrapper.js",
|
||||||
|
|
@ -11,27 +27,43 @@
|
||||||
"build": "node tools/cli.js build",
|
"build": "node tools/cli.js build",
|
||||||
"build:agents": "node tools/cli.js build --agents-only",
|
"build:agents": "node tools/cli.js build --agents-only",
|
||||||
"build:teams": "node tools/cli.js build --teams-only",
|
"build:teams": "node tools/cli.js build --teams-only",
|
||||||
"list:agents": "node tools/cli.js list:agents",
|
|
||||||
"validate": "node tools/cli.js validate",
|
|
||||||
"flatten": "node tools/flattener/main.js",
|
"flatten": "node tools/flattener/main.js",
|
||||||
|
"format": "prettier --write \"**/*.{js,cjs,mjs,json,md,yml,yaml}\"",
|
||||||
|
"format:check": "prettier --check \"**/*.{js,cjs,mjs,json,md,yml,yaml}\"",
|
||||||
"install:bmad": "node tools/installer/bin/bmad.js install",
|
"install:bmad": "node tools/installer/bin/bmad.js install",
|
||||||
"format": "prettier --write \"**/*.md\"",
|
"lint": "eslint . --ext .js,.cjs,.mjs,.yml,.yaml --max-warnings=0",
|
||||||
"version:patch": "node tools/version-bump.js patch",
|
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yml,.yaml --fix",
|
||||||
"version:minor": "node tools/version-bump.js minor",
|
"list:agents": "node tools/cli.js list:agents",
|
||||||
"version:major": "node tools/version-bump.js major",
|
"prepare": "husky",
|
||||||
"version:expansion": "node tools/bump-expansion-version.js",
|
|
||||||
"version:expansion:set": "node tools/update-expansion-version.js",
|
|
||||||
"version:all": "node tools/bump-all-versions.js",
|
|
||||||
"version:all:minor": "node tools/bump-all-versions.js minor",
|
|
||||||
"version:all:major": "node tools/bump-all-versions.js major",
|
|
||||||
"version:all:patch": "node tools/bump-all-versions.js patch",
|
|
||||||
"version:expansion:all": "node tools/bump-all-versions.js",
|
|
||||||
"version:expansion:all:minor": "node tools/bump-all-versions.js minor",
|
|
||||||
"version:expansion:all:major": "node tools/bump-all-versions.js major",
|
|
||||||
"version:expansion:all:patch": "node tools/bump-all-versions.js patch",
|
|
||||||
"release": "semantic-release",
|
"release": "semantic-release",
|
||||||
"release:test": "semantic-release --dry-run --no-ci || echo 'Config test complete - authentication errors are expected locally'",
|
"release:test": "semantic-release --dry-run --no-ci || echo 'Config test complete - authentication errors are expected locally'",
|
||||||
"prepare": "husky"
|
"validate": "node tools/cli.js validate",
|
||||||
|
"version:all": "node tools/bump-all-versions.js",
|
||||||
|
"version:all:major": "node tools/bump-all-versions.js major",
|
||||||
|
"version:all:minor": "node tools/bump-all-versions.js minor",
|
||||||
|
"version:all:patch": "node tools/bump-all-versions.js patch",
|
||||||
|
"version:expansion": "node tools/bump-expansion-version.js",
|
||||||
|
"version:expansion:all": "node tools/bump-all-versions.js",
|
||||||
|
"version:expansion:all:major": "node tools/bump-all-versions.js major",
|
||||||
|
"version:expansion:all:minor": "node tools/bump-all-versions.js minor",
|
||||||
|
"version:expansion:all:patch": "node tools/bump-all-versions.js patch",
|
||||||
|
"version:expansion:set": "node tools/update-expansion-version.js",
|
||||||
|
"version:major": "node tools/version-bump.js major",
|
||||||
|
"version:minor": "node tools/version-bump.js minor",
|
||||||
|
"version:patch": "node tools/version-bump.js patch"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"**/*.{js,cjs,mjs}": [
|
||||||
|
"eslint --fix --max-warnings=0",
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"**/*.{yml,yaml}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"**/*.{json,md}": [
|
||||||
|
"prettier --write"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kayvan/markdown-tree-parser": "^1.5.0",
|
"@kayvan/markdown-tree-parser": "^1.5.0",
|
||||||
|
|
@ -45,37 +77,25 @@
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"ora": "^5.4.1"
|
"ora": "^5.4.1"
|
||||||
},
|
},
|
||||||
"keywords": [
|
|
||||||
"agile",
|
|
||||||
"ai",
|
|
||||||
"orchestrator",
|
|
||||||
"development",
|
|
||||||
"methodology",
|
|
||||||
"agents",
|
|
||||||
"bmad"
|
|
||||||
],
|
|
||||||
"author": "Brian (BMad) Madison",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/bmadcode/BMAD-METHOD.git"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.33.0",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
|
"eslint": "^9.33.0",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
"eslint-plugin-n": "^17.21.3",
|
||||||
|
"eslint-plugin-unicorn": "^60.0.0",
|
||||||
|
"eslint-plugin-yml": "^1.18.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jest": "^30.0.4",
|
"jest": "^30.0.4",
|
||||||
"lint-staged": "^16.1.1",
|
"lint-staged": "^16.1.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
|
"prettier-plugin-packagejson": "^2.5.19",
|
||||||
"semantic-release": "^22.0.0",
|
"semantic-release": "^22.0.0",
|
||||||
|
"yaml-eslint-parser": "^1.2.3",
|
||||||
"yaml-lint": "^1.7.0"
|
"yaml-lint": "^1.7.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"engines": {
|
||||||
"**/*.md": [
|
"node": ">=20.10.0"
|
||||||
"prettier --write"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
export default {
|
||||||
|
$schema: 'https://json.schemastore.org/prettierrc',
|
||||||
|
printWidth: 100,
|
||||||
|
tabWidth: 2,
|
||||||
|
useTabs: false,
|
||||||
|
semi: true,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'all',
|
||||||
|
bracketSpacing: true,
|
||||||
|
arrowParens: 'always',
|
||||||
|
endOfLine: 'lf',
|
||||||
|
proseWrap: 'preserve',
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['*.md'],
|
||||||
|
options: { proseWrap: 'preserve' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['*.yml', '*.yaml'],
|
||||||
|
options: { singleQuote: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['*.json', '*.jsonc'],
|
||||||
|
options: { singleQuote: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['*.cjs'],
|
||||||
|
options: { parser: 'babel' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
plugins: ['prettier-plugin-packagejson'],
|
||||||
|
};
|
||||||
|
|
@ -5,16 +5,16 @@
|
||||||
* This file ensures proper execution when run via npx from GitHub
|
* This file ensures proper execution when run via npx from GitHub
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require('node:child_process');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
const fs = require('fs');
|
const fs = require('node:fs');
|
||||||
|
|
||||||
// Check if we're running in an npx temporary directory
|
// Check if we're running in an npx temporary directory
|
||||||
const isNpxExecution = __dirname.includes('_npx') || __dirname.includes('.npm');
|
const isNpxExecution = __dirname.includes('_npx') || __dirname.includes('.npm');
|
||||||
|
|
||||||
// If running via npx, we need to handle things differently
|
// If running via npx, we need to handle things differently
|
||||||
if (isNpxExecution) {
|
if (isNpxExecution) {
|
||||||
const args = process.argv.slice(2);
|
const arguments_ = process.argv.slice(2);
|
||||||
|
|
||||||
// Use the installer for all commands
|
// Use the installer for all commands
|
||||||
const bmadScriptPath = path.join(__dirname, 'installer', 'bin', 'bmad.js');
|
const bmadScriptPath = path.join(__dirname, 'installer', 'bin', 'bmad.js');
|
||||||
|
|
@ -26,9 +26,9 @@ if (isNpxExecution) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync(`node "${bmadScriptPath}" ${args.join(' ')}`, {
|
execSync(`node "${bmadScriptPath}" ${arguments_.join(' ')}`, {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
cwd: path.dirname(__dirname)
|
cwd: path.dirname(__dirname),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
process.exit(error.status || 1);
|
process.exit(error.status || 1);
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
const fs = require("node:fs").promises;
|
const fs = require('node:fs').promises;
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const DependencyResolver = require("../lib/dependency-resolver");
|
const DependencyResolver = require('../lib/dependency-resolver');
|
||||||
const yamlUtils = require("../lib/yaml-utils");
|
const yamlUtilities = require('../lib/yaml-utils');
|
||||||
|
|
||||||
class WebBuilder {
|
class WebBuilder {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.rootDir = options.rootDir || process.cwd();
|
this.rootDir = options.rootDir || process.cwd();
|
||||||
this.outputDirs = options.outputDirs || [path.join(this.rootDir, "dist")];
|
this.outputDirs = options.outputDirs || [path.join(this.rootDir, 'dist')];
|
||||||
this.resolver = new DependencyResolver(this.rootDir);
|
this.resolver = new DependencyResolver(this.rootDir);
|
||||||
this.templatePath = path.join(
|
this.templatePath = path.join(
|
||||||
this.rootDir,
|
this.rootDir,
|
||||||
"tools",
|
'tools',
|
||||||
"md-assets",
|
'md-assets',
|
||||||
"web-agent-startup-instructions.md"
|
'web-agent-startup-instructions.md',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseYaml(content) {
|
parseYaml(content) {
|
||||||
const yaml = require("js-yaml");
|
const yaml = require('js-yaml');
|
||||||
return yaml.load(content);
|
return yaml.load(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,11 +42,21 @@ class WebBuilder {
|
||||||
generateWebInstructions(bundleType, packName = null) {
|
generateWebInstructions(bundleType, packName = null) {
|
||||||
// Generate dynamic web instructions based on bundle type
|
// Generate dynamic web instructions based on bundle type
|
||||||
const rootExample = packName ? `.${packName}` : '.bmad-core';
|
const rootExample = packName ? `.${packName}` : '.bmad-core';
|
||||||
const examplePath = packName ? `.${packName}/folder/filename.md` : '.bmad-core/folder/filename.md';
|
const examplePath = packName
|
||||||
const personasExample = packName ? `.${packName}/personas/analyst.md` : '.bmad-core/personas/analyst.md';
|
? `.${packName}/folder/filename.md`
|
||||||
const tasksExample = packName ? `.${packName}/tasks/create-story.md` : '.bmad-core/tasks/create-story.md';
|
: '.bmad-core/folder/filename.md';
|
||||||
const utilsExample = packName ? `.${packName}/utils/template-format.md` : '.bmad-core/utils/template-format.md';
|
const personasExample = packName
|
||||||
const tasksRef = packName ? `.${packName}/tasks/create-story.md` : '.bmad-core/tasks/create-story.md';
|
? `.${packName}/personas/analyst.md`
|
||||||
|
: '.bmad-core/personas/analyst.md';
|
||||||
|
const tasksExample = packName
|
||||||
|
? `.${packName}/tasks/create-story.md`
|
||||||
|
: '.bmad-core/tasks/create-story.md';
|
||||||
|
const utilitiesExample = packName
|
||||||
|
? `.${packName}/utils/template-format.md`
|
||||||
|
: '.bmad-core/utils/template-format.md';
|
||||||
|
const tasksReference = packName
|
||||||
|
? `.${packName}/tasks/create-story.md`
|
||||||
|
: '.bmad-core/tasks/create-story.md';
|
||||||
|
|
||||||
return `# Web Agent Bundle Instructions
|
return `# Web Agent Bundle Instructions
|
||||||
|
|
||||||
|
|
@ -79,8 +89,8 @@ dependencies:
|
||||||
|
|
||||||
These references map directly to bundle sections:
|
These references map directly to bundle sections:
|
||||||
|
|
||||||
- \`utils: template-format\` → Look for \`==================== START: ${utilsExample} ====================\`
|
- \`utils: template-format\` → Look for \`==================== START: ${utilitiesExample} ====================\`
|
||||||
- \`tasks: create-story\` → Look for \`==================== START: ${tasksRef} ====================\`
|
- \`tasks: create-story\` → Look for \`==================== START: ${tasksReference} ====================\`
|
||||||
|
|
||||||
3. **Execution Context**: You are operating in a web environment. All your capabilities and knowledge are contained within this bundle. Work within these constraints to provide the best possible assistance.
|
3. **Execution Context**: You are operating in a web environment. All your capabilities and knowledge are contained within this bundle. Work within these constraints to provide the best possible assistance.
|
||||||
|
|
||||||
|
|
@ -112,10 +122,10 @@ These references map directly to bundle sections:
|
||||||
|
|
||||||
// Write to all output directories
|
// Write to all output directories
|
||||||
for (const outputDir of this.outputDirs) {
|
for (const outputDir of this.outputDirs) {
|
||||||
const outputPath = path.join(outputDir, "agents");
|
const outputPath = path.join(outputDir, 'agents');
|
||||||
await fs.mkdir(outputPath, { recursive: true });
|
await fs.mkdir(outputPath, { recursive: true });
|
||||||
const outputFile = path.join(outputPath, `${agentId}.txt`);
|
const outputFile = path.join(outputPath, `${agentId}.txt`);
|
||||||
await fs.writeFile(outputFile, bundle, "utf8");
|
await fs.writeFile(outputFile, bundle, 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,10 +141,10 @@ These references map directly to bundle sections:
|
||||||
|
|
||||||
// Write to all output directories
|
// Write to all output directories
|
||||||
for (const outputDir of this.outputDirs) {
|
for (const outputDir of this.outputDirs) {
|
||||||
const outputPath = path.join(outputDir, "teams");
|
const outputPath = path.join(outputDir, 'teams');
|
||||||
await fs.mkdir(outputPath, { recursive: true });
|
await fs.mkdir(outputPath, { recursive: true });
|
||||||
const outputFile = path.join(outputPath, `${teamId}.txt`);
|
const outputFile = path.join(outputPath, `${teamId}.txt`);
|
||||||
await fs.writeFile(outputFile, bundle, "utf8");
|
await fs.writeFile(outputFile, bundle, 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +167,7 @@ These references map directly to bundle sections:
|
||||||
sections.push(this.formatSection(resourcePath, resource.content, 'bmad-core'));
|
sections.push(this.formatSection(resourcePath, resource.content, 'bmad-core'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections.join("\n");
|
return sections.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildTeamBundle(teamId) {
|
async buildTeamBundle(teamId) {
|
||||||
|
|
@ -182,12 +192,12 @@ These references map directly to bundle sections:
|
||||||
sections.push(this.formatSection(resourcePath, resource.content, 'bmad-core'));
|
sections.push(this.formatSection(resourcePath, resource.content, 'bmad-core'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections.join("\n");
|
return sections.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
processAgentContent(content) {
|
processAgentContent(content) {
|
||||||
// First, replace content before YAML with the template
|
// First, replace content before YAML with the template
|
||||||
const yamlContent = yamlUtils.extractYamlFromAgent(content);
|
const yamlContent = yamlUtilities.extractYamlFromAgent(content);
|
||||||
if (!yamlContent) return content;
|
if (!yamlContent) return content;
|
||||||
|
|
||||||
const yamlMatch = content.match(/```ya?ml\n([\s\S]*?)\n```/);
|
const yamlMatch = content.match(/```ya?ml\n([\s\S]*?)\n```/);
|
||||||
|
|
@ -198,24 +208,24 @@ These references map directly to bundle sections:
|
||||||
|
|
||||||
// Parse YAML and remove root and IDE-FILE-RESOLUTION properties
|
// Parse YAML and remove root and IDE-FILE-RESOLUTION properties
|
||||||
try {
|
try {
|
||||||
const yaml = require("js-yaml");
|
const yaml = require('js-yaml');
|
||||||
const parsed = yaml.load(yamlContent);
|
const parsed = yaml.load(yamlContent);
|
||||||
|
|
||||||
// Remove the properties if they exist at root level
|
// Remove the properties if they exist at root level
|
||||||
delete parsed.root;
|
delete parsed.root;
|
||||||
delete parsed["IDE-FILE-RESOLUTION"];
|
delete parsed['IDE-FILE-RESOLUTION'];
|
||||||
delete parsed["REQUEST-RESOLUTION"];
|
delete parsed['REQUEST-RESOLUTION'];
|
||||||
|
|
||||||
// Also remove from activation-instructions if they exist
|
// Also remove from activation-instructions if they exist
|
||||||
if (parsed["activation-instructions"] && Array.isArray(parsed["activation-instructions"])) {
|
if (parsed['activation-instructions'] && Array.isArray(parsed['activation-instructions'])) {
|
||||||
parsed["activation-instructions"] = parsed["activation-instructions"].filter(
|
parsed['activation-instructions'] = parsed['activation-instructions'].filter(
|
||||||
(instruction) => {
|
(instruction) => {
|
||||||
return (
|
return (
|
||||||
typeof instruction === 'string' &&
|
typeof instruction === 'string' &&
|
||||||
!instruction.startsWith("IDE-FILE-RESOLUTION:") &&
|
!instruction.startsWith('IDE-FILE-RESOLUTION:') &&
|
||||||
!instruction.startsWith("REQUEST-RESOLUTION:")
|
!instruction.startsWith('REQUEST-RESOLUTION:')
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,25 +233,25 @@ These references map directly to bundle sections:
|
||||||
const cleanedYaml = yaml.dump(parsed, { lineWidth: -1 });
|
const cleanedYaml = yaml.dump(parsed, { lineWidth: -1 });
|
||||||
|
|
||||||
// Get the agent name from the YAML for the header
|
// Get the agent name from the YAML for the header
|
||||||
const agentName = parsed.agent?.id || "agent";
|
const agentName = parsed.agent?.id || 'agent';
|
||||||
|
|
||||||
// Build the new content with just the agent header and YAML
|
// Build the new content with just the agent header and YAML
|
||||||
const newHeader = `# ${agentName}\n\nCRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n`;
|
const newHeader = `# ${agentName}\n\nCRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n`;
|
||||||
const afterYaml = content.substring(yamlEndIndex);
|
const afterYaml = content.slice(Math.max(0, yamlEndIndex));
|
||||||
|
|
||||||
return newHeader + "```yaml\n" + cleanedYaml.trim() + "\n```" + afterYaml;
|
return newHeader + '```yaml\n' + cleanedYaml.trim() + '\n```' + afterYaml;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("Failed to process agent YAML:", error.message);
|
console.warn('Failed to process agent YAML:', error.message);
|
||||||
// If parsing fails, return original content
|
// If parsing fails, return original content
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatSection(path, content, bundleRoot = 'bmad-core') {
|
formatSection(path, content, bundleRoot = 'bmad-core') {
|
||||||
const separator = "====================";
|
const separator = '====================';
|
||||||
|
|
||||||
// Process agent content if this is an agent file
|
// Process agent content if this is an agent file
|
||||||
if (path.includes("/agents/")) {
|
if (path.includes('/agents/')) {
|
||||||
content = this.processAgentContent(content);
|
content = this.processAgentContent(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,17 +262,17 @@ These references map directly to bundle sections:
|
||||||
`${separator} START: ${path} ${separator}`,
|
`${separator} START: ${path} ${separator}`,
|
||||||
content.trim(),
|
content.trim(),
|
||||||
`${separator} END: ${path} ${separator}`,
|
`${separator} END: ${path} ${separator}`,
|
||||||
"",
|
'',
|
||||||
].join("\n");
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceRootReferences(content, bundleRoot) {
|
replaceRootReferences(content, bundleRoot) {
|
||||||
// Replace {root} with the appropriate bundle root path
|
// Replace {root} with the appropriate bundle root path
|
||||||
return content.replace(/\{root\}/g, `.${bundleRoot}`);
|
return content.replaceAll('{root}', `.${bundleRoot}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async validate() {
|
async validate() {
|
||||||
console.log("Validating agent configurations...");
|
console.log('Validating agent configurations...');
|
||||||
const agents = await this.resolver.listAgents();
|
const agents = await this.resolver.listAgents();
|
||||||
for (const agentId of agents) {
|
for (const agentId of agents) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -274,7 +284,7 @@ These references map directly to bundle sections:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("\nValidating team configurations...");
|
console.log('\nValidating team configurations...');
|
||||||
const teams = await this.resolver.listTeams();
|
const teams = await this.resolver.listTeams();
|
||||||
for (const teamId of teams) {
|
for (const teamId of teams) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -299,54 +309,54 @@ These references map directly to bundle sections:
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildExpansionPack(packName, options = {}) {
|
async buildExpansionPack(packName, options = {}) {
|
||||||
const packDir = path.join(this.rootDir, "expansion-packs", packName);
|
const packDir = path.join(this.rootDir, 'expansion-packs', packName);
|
||||||
const outputDirs = [path.join(this.rootDir, "dist", "expansion-packs", packName)];
|
const outputDirectories = [path.join(this.rootDir, 'dist', 'expansion-packs', packName)];
|
||||||
|
|
||||||
// Clean output directories if requested
|
// Clean output directories if requested
|
||||||
if (options.clean !== false) {
|
if (options.clean !== false) {
|
||||||
for (const outputDir of outputDirs) {
|
for (const outputDir of outputDirectories) {
|
||||||
try {
|
try {
|
||||||
await fs.rm(outputDir, { recursive: true, force: true });
|
await fs.rm(outputDir, { recursive: true, force: true });
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Directory might not exist, that's fine
|
// Directory might not exist, that's fine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build individual agents first
|
// Build individual agents first
|
||||||
const agentsDir = path.join(packDir, "agents");
|
const agentsDir = path.join(packDir, 'agents');
|
||||||
try {
|
try {
|
||||||
const agentFiles = await fs.readdir(agentsDir);
|
const agentFiles = await fs.readdir(agentsDir);
|
||||||
const agentMarkdownFiles = agentFiles.filter((f) => f.endsWith(".md"));
|
const agentMarkdownFiles = agentFiles.filter((f) => f.endsWith('.md'));
|
||||||
|
|
||||||
if (agentMarkdownFiles.length > 0) {
|
if (agentMarkdownFiles.length > 0) {
|
||||||
console.log(` Building individual agents for ${packName}:`);
|
console.log(` Building individual agents for ${packName}:`);
|
||||||
|
|
||||||
for (const agentFile of agentMarkdownFiles) {
|
for (const agentFile of agentMarkdownFiles) {
|
||||||
const agentName = agentFile.replace(".md", "");
|
const agentName = agentFile.replace('.md', '');
|
||||||
console.log(` - ${agentName}`);
|
console.log(` - ${agentName}`);
|
||||||
|
|
||||||
// Build individual agent bundle
|
// Build individual agent bundle
|
||||||
const bundle = await this.buildExpansionAgentBundle(packName, packDir, agentName);
|
const bundle = await this.buildExpansionAgentBundle(packName, packDir, agentName);
|
||||||
|
|
||||||
// Write to all output directories
|
// Write to all output directories
|
||||||
for (const outputDir of outputDirs) {
|
for (const outputDir of outputDirectories) {
|
||||||
const agentsOutputDir = path.join(outputDir, "agents");
|
const agentsOutputDir = path.join(outputDir, 'agents');
|
||||||
await fs.mkdir(agentsOutputDir, { recursive: true });
|
await fs.mkdir(agentsOutputDir, { recursive: true });
|
||||||
const outputFile = path.join(agentsOutputDir, `${agentName}.txt`);
|
const outputFile = path.join(agentsOutputDir, `${agentName}.txt`);
|
||||||
await fs.writeFile(outputFile, bundle, "utf8");
|
await fs.writeFile(outputFile, bundle, 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.debug(` No agents directory found for ${packName}`);
|
console.debug(` No agents directory found for ${packName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build team bundle
|
// Build team bundle
|
||||||
const agentTeamsDir = path.join(packDir, "agent-teams");
|
const agentTeamsDir = path.join(packDir, 'agent-teams');
|
||||||
try {
|
try {
|
||||||
const teamFiles = await fs.readdir(agentTeamsDir);
|
const teamFiles = await fs.readdir(agentTeamsDir);
|
||||||
const teamFile = teamFiles.find((f) => f.endsWith(".yaml"));
|
const teamFile = teamFiles.find((f) => f.endsWith('.yaml'));
|
||||||
|
|
||||||
if (teamFile) {
|
if (teamFile) {
|
||||||
console.log(` Building team bundle for ${packName}`);
|
console.log(` Building team bundle for ${packName}`);
|
||||||
|
|
@ -356,17 +366,17 @@ These references map directly to bundle sections:
|
||||||
const bundle = await this.buildExpansionTeamBundle(packName, packDir, teamConfigPath);
|
const bundle = await this.buildExpansionTeamBundle(packName, packDir, teamConfigPath);
|
||||||
|
|
||||||
// Write to all output directories
|
// Write to all output directories
|
||||||
for (const outputDir of outputDirs) {
|
for (const outputDir of outputDirectories) {
|
||||||
const teamsOutputDir = path.join(outputDir, "teams");
|
const teamsOutputDir = path.join(outputDir, 'teams');
|
||||||
await fs.mkdir(teamsOutputDir, { recursive: true });
|
await fs.mkdir(teamsOutputDir, { recursive: true });
|
||||||
const outputFile = path.join(teamsOutputDir, teamFile.replace(".yaml", ".txt"));
|
const outputFile = path.join(teamsOutputDir, teamFile.replace('.yaml', '.txt'));
|
||||||
await fs.writeFile(outputFile, bundle, "utf8");
|
await fs.writeFile(outputFile, bundle, 'utf8');
|
||||||
console.log(` ✓ Created bundle: ${path.relative(this.rootDir, outputFile)}`);
|
console.log(` ✓ Created bundle: ${path.relative(this.rootDir, outputFile)}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn(` ⚠ No team configuration found in ${packName}/agent-teams/`);
|
console.warn(` ⚠ No team configuration found in ${packName}/agent-teams/`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.warn(` ⚠ No agent-teams directory found for ${packName}`);
|
console.warn(` ⚠ No agent-teams directory found for ${packName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -376,16 +386,16 @@ These references map directly to bundle sections:
|
||||||
const sections = [template];
|
const sections = [template];
|
||||||
|
|
||||||
// Add agent configuration
|
// Add agent configuration
|
||||||
const agentPath = path.join(packDir, "agents", `${agentName}.md`);
|
const agentPath = path.join(packDir, 'agents', `${agentName}.md`);
|
||||||
const agentContent = await fs.readFile(agentPath, "utf8");
|
const agentContent = await fs.readFile(agentPath, 'utf8');
|
||||||
const agentWebPath = this.convertToWebPath(agentPath, packName);
|
const agentWebPath = this.convertToWebPath(agentPath, packName);
|
||||||
sections.push(this.formatSection(agentWebPath, agentContent, packName));
|
sections.push(this.formatSection(agentWebPath, agentContent, packName));
|
||||||
|
|
||||||
// Resolve and add agent dependencies
|
// Resolve and add agent dependencies
|
||||||
const yamlContent = yamlUtils.extractYamlFromAgent(agentContent);
|
const yamlContent = yamlUtilities.extractYamlFromAgent(agentContent);
|
||||||
if (yamlContent) {
|
if (yamlContent) {
|
||||||
try {
|
try {
|
||||||
const yaml = require("js-yaml");
|
const yaml = require('js-yaml');
|
||||||
const agentConfig = yaml.load(yamlContent);
|
const agentConfig = yaml.load(yamlContent);
|
||||||
|
|
||||||
if (agentConfig.dependencies) {
|
if (agentConfig.dependencies) {
|
||||||
|
|
@ -398,59 +408,43 @@ These references map directly to bundle sections:
|
||||||
// Try expansion pack first
|
// Try expansion pack first
|
||||||
const resourcePath = path.join(packDir, resourceType, resourceName);
|
const resourcePath = path.join(packDir, resourceType, resourceName);
|
||||||
try {
|
try {
|
||||||
const resourceContent = await fs.readFile(resourcePath, "utf8");
|
const resourceContent = await fs.readFile(resourcePath, 'utf8');
|
||||||
const resourceWebPath = this.convertToWebPath(resourcePath, packName);
|
const resourceWebPath = this.convertToWebPath(resourcePath, packName);
|
||||||
sections.push(
|
sections.push(this.formatSection(resourceWebPath, resourceContent, packName));
|
||||||
this.formatSection(resourceWebPath, resourceContent, packName)
|
|
||||||
);
|
|
||||||
found = true;
|
found = true;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Not in expansion pack, continue
|
// Not in expansion pack, continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found in expansion pack, try core
|
// If not found in expansion pack, try core
|
||||||
if (!found) {
|
if (!found) {
|
||||||
const corePath = path.join(
|
const corePath = path.join(this.rootDir, 'bmad-core', resourceType, resourceName);
|
||||||
this.rootDir,
|
|
||||||
"bmad-core",
|
|
||||||
resourceType,
|
|
||||||
resourceName
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
const coreContent = await fs.readFile(corePath, "utf8");
|
const coreContent = await fs.readFile(corePath, 'utf8');
|
||||||
const coreWebPath = this.convertToWebPath(corePath, packName);
|
const coreWebPath = this.convertToWebPath(corePath, packName);
|
||||||
sections.push(
|
sections.push(this.formatSection(coreWebPath, coreContent, packName));
|
||||||
this.formatSection(coreWebPath, coreContent, packName)
|
|
||||||
);
|
|
||||||
found = true;
|
found = true;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Not in core either, continue
|
// Not in core either, continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found in core, try common folder
|
// If not found in core, try common folder
|
||||||
if (!found) {
|
if (!found) {
|
||||||
const commonPath = path.join(
|
const commonPath = path.join(this.rootDir, 'common', resourceType, resourceName);
|
||||||
this.rootDir,
|
|
||||||
"common",
|
|
||||||
resourceType,
|
|
||||||
resourceName
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
const commonContent = await fs.readFile(commonPath, "utf8");
|
const commonContent = await fs.readFile(commonPath, 'utf8');
|
||||||
const commonWebPath = this.convertToWebPath(commonPath, packName);
|
const commonWebPath = this.convertToWebPath(commonPath, packName);
|
||||||
sections.push(
|
sections.push(this.formatSection(commonWebPath, commonContent, packName));
|
||||||
this.formatSection(commonWebPath, commonContent, packName)
|
|
||||||
);
|
|
||||||
found = true;
|
found = true;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Not in common either, continue
|
// Not in common either, continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
console.warn(
|
console.warn(
|
||||||
` ⚠ Dependency ${resourceType}#${resourceName} not found in expansion pack or core`
|
` ⚠ Dependency ${resourceType}#${resourceName} not found in expansion pack or core`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -462,7 +456,7 @@ These references map directly to bundle sections:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections.join("\n");
|
return sections.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildExpansionTeamBundle(packName, packDir, teamConfigPath) {
|
async buildExpansionTeamBundle(packName, packDir, teamConfigPath) {
|
||||||
|
|
@ -471,38 +465,38 @@ These references map directly to bundle sections:
|
||||||
const sections = [template];
|
const sections = [template];
|
||||||
|
|
||||||
// Add team configuration and parse to get agent list
|
// Add team configuration and parse to get agent list
|
||||||
const teamContent = await fs.readFile(teamConfigPath, "utf8");
|
const teamContent = await fs.readFile(teamConfigPath, 'utf8');
|
||||||
const teamFileName = path.basename(teamConfigPath, ".yaml");
|
const teamFileName = path.basename(teamConfigPath, '.yaml');
|
||||||
const teamConfig = this.parseYaml(teamContent);
|
const teamConfig = this.parseYaml(teamContent);
|
||||||
const teamWebPath = this.convertToWebPath(teamConfigPath, packName);
|
const teamWebPath = this.convertToWebPath(teamConfigPath, packName);
|
||||||
sections.push(this.formatSection(teamWebPath, teamContent, packName));
|
sections.push(this.formatSection(teamWebPath, teamContent, packName));
|
||||||
|
|
||||||
// Get list of expansion pack agents
|
// Get list of expansion pack agents
|
||||||
const expansionAgents = new Set();
|
const expansionAgents = new Set();
|
||||||
const agentsDir = path.join(packDir, "agents");
|
const agentsDir = path.join(packDir, 'agents');
|
||||||
try {
|
try {
|
||||||
const agentFiles = await fs.readdir(agentsDir);
|
const agentFiles = await fs.readdir(agentsDir);
|
||||||
for (const agentFile of agentFiles.filter((f) => f.endsWith(".md"))) {
|
for (const agentFile of agentFiles.filter((f) => f.endsWith('.md'))) {
|
||||||
const agentName = agentFile.replace(".md", "");
|
const agentName = agentFile.replace('.md', '');
|
||||||
expansionAgents.add(agentName);
|
expansionAgents.add(agentName);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.warn(` ⚠ No agents directory found in ${packName}`);
|
console.warn(` ⚠ No agents directory found in ${packName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a map of all available expansion pack resources for override checking
|
// Build a map of all available expansion pack resources for override checking
|
||||||
const expansionResources = new Map();
|
const expansionResources = new Map();
|
||||||
const resourceDirs = ["templates", "tasks", "checklists", "workflows", "data"];
|
const resourceDirectories = ['templates', 'tasks', 'checklists', 'workflows', 'data'];
|
||||||
for (const resourceDir of resourceDirs) {
|
for (const resourceDir of resourceDirectories) {
|
||||||
const resourcePath = path.join(packDir, resourceDir);
|
const resourcePath = path.join(packDir, resourceDir);
|
||||||
try {
|
try {
|
||||||
const resourceFiles = await fs.readdir(resourcePath);
|
const resourceFiles = await fs.readdir(resourcePath);
|
||||||
for (const resourceFile of resourceFiles.filter(
|
for (const resourceFile of resourceFiles.filter(
|
||||||
(f) => f.endsWith(".md") || f.endsWith(".yaml")
|
(f) => f.endsWith('.md') || f.endsWith('.yaml'),
|
||||||
)) {
|
)) {
|
||||||
expansionResources.set(`${resourceDir}#${resourceFile}`, true);
|
expansionResources.set(`${resourceDir}#${resourceFile}`, true);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Directory might not exist, that's fine
|
// Directory might not exist, that's fine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -511,9 +505,9 @@ These references map directly to bundle sections:
|
||||||
const agentsToProcess = teamConfig.agents || [];
|
const agentsToProcess = teamConfig.agents || [];
|
||||||
|
|
||||||
// Ensure bmad-orchestrator is always included for teams
|
// Ensure bmad-orchestrator is always included for teams
|
||||||
if (!agentsToProcess.includes("bmad-orchestrator")) {
|
if (!agentsToProcess.includes('bmad-orchestrator')) {
|
||||||
console.warn(` ⚠ Team ${teamFileName} missing bmad-orchestrator, adding automatically`);
|
console.warn(` ⚠ Team ${teamFileName} missing bmad-orchestrator, adding automatically`);
|
||||||
agentsToProcess.unshift("bmad-orchestrator");
|
agentsToProcess.unshift('bmad-orchestrator');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track all dependencies from all agents (deduplicated)
|
// Track all dependencies from all agents (deduplicated)
|
||||||
|
|
@ -523,7 +517,7 @@ These references map directly to bundle sections:
|
||||||
if (expansionAgents.has(agentId)) {
|
if (expansionAgents.has(agentId)) {
|
||||||
// Use expansion pack version (override)
|
// Use expansion pack version (override)
|
||||||
const agentPath = path.join(agentsDir, `${agentId}.md`);
|
const agentPath = path.join(agentsDir, `${agentId}.md`);
|
||||||
const agentContent = await fs.readFile(agentPath, "utf8");
|
const agentContent = await fs.readFile(agentPath, 'utf8');
|
||||||
const expansionAgentWebPath = this.convertToWebPath(agentPath, packName);
|
const expansionAgentWebPath = this.convertToWebPath(agentPath, packName);
|
||||||
sections.push(this.formatSection(expansionAgentWebPath, agentContent, packName));
|
sections.push(this.formatSection(expansionAgentWebPath, agentContent, packName));
|
||||||
|
|
||||||
|
|
@ -551,13 +545,13 @@ These references map directly to bundle sections:
|
||||||
} else {
|
} else {
|
||||||
// Use core BMad version
|
// Use core BMad version
|
||||||
try {
|
try {
|
||||||
const coreAgentPath = path.join(this.rootDir, "bmad-core", "agents", `${agentId}.md`);
|
const coreAgentPath = path.join(this.rootDir, 'bmad-core', 'agents', `${agentId}.md`);
|
||||||
const coreAgentContent = await fs.readFile(coreAgentPath, "utf8");
|
const coreAgentContent = await fs.readFile(coreAgentPath, 'utf8');
|
||||||
const coreAgentWebPath = this.convertToWebPath(coreAgentPath, packName);
|
const coreAgentWebPath = this.convertToWebPath(coreAgentPath, packName);
|
||||||
sections.push(this.formatSection(coreAgentWebPath, coreAgentContent, packName));
|
sections.push(this.formatSection(coreAgentWebPath, coreAgentContent, packName));
|
||||||
|
|
||||||
// Parse and collect dependencies from core agent
|
// Parse and collect dependencies from core agent
|
||||||
const yamlContent = yamlUtils.extractYamlFromAgent(coreAgentContent, true);
|
const yamlContent = yamlUtilities.extractYamlFromAgent(coreAgentContent, true);
|
||||||
if (yamlContent) {
|
if (yamlContent) {
|
||||||
try {
|
try {
|
||||||
const agentConfig = this.parseYaml(yamlContent);
|
const agentConfig = this.parseYaml(yamlContent);
|
||||||
|
|
@ -577,7 +571,7 @@ These references map directly to bundle sections:
|
||||||
console.debug(`Failed to parse agent YAML for ${agentId}:`, error.message);
|
console.debug(`Failed to parse agent YAML for ${agentId}:`, error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.warn(` ⚠ Agent ${agentId} not found in core or expansion pack`);
|
console.warn(` ⚠ Agent ${agentId} not found in core or expansion pack`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -593,38 +587,38 @@ These references map directly to bundle sections:
|
||||||
// We know it exists in expansion pack, find and load it
|
// We know it exists in expansion pack, find and load it
|
||||||
const expansionPath = path.join(packDir, dep.type, dep.name);
|
const expansionPath = path.join(packDir, dep.type, dep.name);
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(expansionPath, "utf8");
|
const content = await fs.readFile(expansionPath, 'utf8');
|
||||||
const expansionWebPath = this.convertToWebPath(expansionPath, packName);
|
const expansionWebPath = this.convertToWebPath(expansionPath, packName);
|
||||||
sections.push(this.formatSection(expansionWebPath, content, packName));
|
sections.push(this.formatSection(expansionWebPath, content, packName));
|
||||||
console.log(` ✓ Using expansion override for ${key}`);
|
console.log(` ✓ Using expansion override for ${key}`);
|
||||||
found = true;
|
found = true;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Try next extension
|
// Try next extension
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found in expansion pack (or doesn't exist there), try core
|
// If not found in expansion pack (or doesn't exist there), try core
|
||||||
if (!found) {
|
if (!found) {
|
||||||
const corePath = path.join(this.rootDir, "bmad-core", dep.type, dep.name);
|
const corePath = path.join(this.rootDir, 'bmad-core', dep.type, dep.name);
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(corePath, "utf8");
|
const content = await fs.readFile(corePath, 'utf8');
|
||||||
const coreWebPath = this.convertToWebPath(corePath, packName);
|
const coreWebPath = this.convertToWebPath(corePath, packName);
|
||||||
sections.push(this.formatSection(coreWebPath, content, packName));
|
sections.push(this.formatSection(coreWebPath, content, packName));
|
||||||
found = true;
|
found = true;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Not in core either, continue
|
// Not in core either, continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found in core, try common folder
|
// If not found in core, try common folder
|
||||||
if (!found) {
|
if (!found) {
|
||||||
const commonPath = path.join(this.rootDir, "common", dep.type, dep.name);
|
const commonPath = path.join(this.rootDir, 'common', dep.type, dep.name);
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(commonPath, "utf8");
|
const content = await fs.readFile(commonPath, 'utf8');
|
||||||
const commonWebPath = this.convertToWebPath(commonPath, packName);
|
const commonWebPath = this.convertToWebPath(commonPath, packName);
|
||||||
sections.push(this.formatSection(commonWebPath, content, packName));
|
sections.push(this.formatSection(commonWebPath, content, packName));
|
||||||
found = true;
|
found = true;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Not in common either, continue
|
// Not in common either, continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,16 +629,16 @@ These references map directly to bundle sections:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add remaining expansion pack resources not already included as dependencies
|
// Add remaining expansion pack resources not already included as dependencies
|
||||||
for (const resourceDir of resourceDirs) {
|
for (const resourceDir of resourceDirectories) {
|
||||||
const resourcePath = path.join(packDir, resourceDir);
|
const resourcePath = path.join(packDir, resourceDir);
|
||||||
try {
|
try {
|
||||||
const resourceFiles = await fs.readdir(resourcePath);
|
const resourceFiles = await fs.readdir(resourcePath);
|
||||||
for (const resourceFile of resourceFiles.filter(
|
for (const resourceFile of resourceFiles.filter(
|
||||||
(f) => f.endsWith(".md") || f.endsWith(".yaml")
|
(f) => f.endsWith('.md') || f.endsWith('.yaml'),
|
||||||
)) {
|
)) {
|
||||||
const filePath = path.join(resourcePath, resourceFile);
|
const filePath = path.join(resourcePath, resourceFile);
|
||||||
const fileContent = await fs.readFile(filePath, "utf8");
|
const fileContent = await fs.readFile(filePath, 'utf8');
|
||||||
const fileName = resourceFile.replace(/\.(md|yaml)$/, "");
|
const fileName = resourceFile.replace(/\.(md|yaml)$/, '');
|
||||||
|
|
||||||
// Only add if not already included as a dependency
|
// Only add if not already included as a dependency
|
||||||
const resourceKey = `${resourceDir}#${fileName}`;
|
const resourceKey = `${resourceDir}#${fileName}`;
|
||||||
|
|
@ -654,21 +648,21 @@ These references map directly to bundle sections:
|
||||||
sections.push(this.formatSection(resourceWebPath, fileContent, packName));
|
sections.push(this.formatSection(resourceWebPath, fileContent, packName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Directory might not exist, that's fine
|
// Directory might not exist, that's fine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections.join("\n");
|
return sections.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async listExpansionPacks() {
|
async listExpansionPacks() {
|
||||||
const expansionPacksDir = path.join(this.rootDir, "expansion-packs");
|
const expansionPacksDir = path.join(this.rootDir, 'expansion-packs');
|
||||||
try {
|
try {
|
||||||
const entries = await fs.readdir(expansionPacksDir, { withFileTypes: true });
|
const entries = await fs.readdir(expansionPacksDir, { withFileTypes: true });
|
||||||
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.warn("No expansion-packs directory found");
|
console.warn('No expansion-packs directory found');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
#!/usr/bin/env node
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
const arguments_ = process.argv.slice(2);
|
||||||
const bumpType = args[0] || 'minor'; // default to minor
|
const bumpType = arguments_[0] || 'minor'; // default to minor
|
||||||
|
|
||||||
if (!['major', 'minor', 'patch'].includes(bumpType)) {
|
if (!['major', 'minor', 'patch'].includes(bumpType)) {
|
||||||
console.log('Usage: node bump-all-versions.js [major|minor|patch]');
|
console.log('Usage: node bump-all-versions.js [major|minor|patch]');
|
||||||
|
|
@ -17,16 +15,20 @@ function bumpVersion(currentVersion, type) {
|
||||||
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'major':
|
case 'major': {
|
||||||
return `${major + 1}.0.0`;
|
return `${major + 1}.0.0`;
|
||||||
case 'minor':
|
}
|
||||||
|
case 'minor': {
|
||||||
return `${major}.${minor + 1}.0`;
|
return `${major}.${minor + 1}.0`;
|
||||||
case 'patch':
|
}
|
||||||
|
case 'patch': {
|
||||||
return `${major}.${minor}.${patch + 1}`;
|
return `${major}.${minor}.${patch + 1}`;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return currentVersion;
|
return currentVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function bumpAllVersions() {
|
async function bumpAllVersions() {
|
||||||
const updatedItems = [];
|
const updatedItems = [];
|
||||||
|
|
@ -43,7 +45,12 @@ async function bumpAllVersions() {
|
||||||
|
|
||||||
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
|
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
|
||||||
|
|
||||||
updatedItems.push({ type: 'core', name: 'BMad Core', oldVersion: oldCoreVersion, newVersion: newCoreVersion });
|
updatedItems.push({
|
||||||
|
type: 'core',
|
||||||
|
name: 'BMad Core',
|
||||||
|
oldVersion: oldCoreVersion,
|
||||||
|
newVersion: newCoreVersion,
|
||||||
|
});
|
||||||
console.log(`✓ BMad Core (package.json): ${oldCoreVersion} → ${newCoreVersion}`);
|
console.log(`✓ BMad Core (package.json): ${oldCoreVersion} → ${newCoreVersion}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`✗ Failed to update BMad Core: ${error.message}`);
|
console.error(`✗ Failed to update BMad Core: ${error.message}`);
|
||||||
|
|
@ -74,7 +81,6 @@ async function bumpAllVersions() {
|
||||||
|
|
||||||
updatedItems.push({ type: 'expansion', name: packId, oldVersion, newVersion });
|
updatedItems.push({ type: 'expansion', name: packId, oldVersion, newVersion });
|
||||||
console.log(`✓ ${packId}: ${oldVersion} → ${newVersion}`);
|
console.log(`✓ ${packId}: ${oldVersion} → ${newVersion}`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`✗ Failed to update ${packId}: ${error.message}`);
|
console.error(`✗ Failed to update ${packId}: ${error.message}`);
|
||||||
}
|
}
|
||||||
|
|
@ -83,20 +89,23 @@ async function bumpAllVersions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatedItems.length > 0) {
|
if (updatedItems.length > 0) {
|
||||||
const coreCount = updatedItems.filter(i => i.type === 'core').length;
|
const coreCount = updatedItems.filter((index) => index.type === 'core').length;
|
||||||
const expansionCount = updatedItems.filter(i => i.type === 'expansion').length;
|
const expansionCount = updatedItems.filter((index) => index.type === 'expansion').length;
|
||||||
|
|
||||||
console.log(`\n✓ Successfully bumped ${updatedItems.length} item(s) with ${bumpType} version bump`);
|
console.log(
|
||||||
|
`\n✓ Successfully bumped ${updatedItems.length} item(s) with ${bumpType} version bump`,
|
||||||
|
);
|
||||||
if (coreCount > 0) console.log(` - ${coreCount} core`);
|
if (coreCount > 0) console.log(` - ${coreCount} core`);
|
||||||
if (expansionCount > 0) console.log(` - ${expansionCount} expansion pack(s)`);
|
if (expansionCount > 0) console.log(` - ${expansionCount} expansion pack(s)`);
|
||||||
|
|
||||||
console.log('\nNext steps:');
|
console.log('\nNext steps:');
|
||||||
console.log('1. Test the changes');
|
console.log('1. Test the changes');
|
||||||
console.log('2. Commit: git add -A && git commit -m "chore: bump all versions (' + bumpType + ')"');
|
console.log(
|
||||||
|
'2. Commit: git add -A && git commit -m "chore: bump all versions (' + bumpType + ')"',
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('No items found to update');
|
console.log('No items found to update');
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error reading expansion packs directory:', error.message);
|
console.error('Error reading expansion packs directory:', error.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
// Load required modules
|
// Load required modules
|
||||||
const fs = require('fs');
|
const fs = require('node:fs');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
// Parse CLI arguments
|
// Parse CLI arguments
|
||||||
const args = process.argv.slice(2);
|
const arguments_ = process.argv.slice(2);
|
||||||
const packId = args[0];
|
const packId = arguments_[0];
|
||||||
const bumpType = args[1] || 'minor';
|
const bumpType = arguments_[1] || 'minor';
|
||||||
|
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (!packId || args.length > 2) {
|
if (!packId || arguments_.length > 2) {
|
||||||
console.log('Usage: node bump-expansion-version.js <expansion-pack-id> [major|minor|patch]');
|
console.log('Usage: node bump-expansion-version.js <expansion-pack-id> [major|minor|patch]');
|
||||||
console.log('Default: minor');
|
console.log('Default: minor');
|
||||||
console.log('Example: node bump-expansion-version.js bmad-creator-tools patch');
|
console.log('Example: node bump-expansion-version.js bmad-creator-tools patch');
|
||||||
|
|
@ -28,10 +26,18 @@ function bumpVersion(currentVersion, type) {
|
||||||
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'major': return `${major + 1}.0.0`;
|
case 'major': {
|
||||||
case 'minor': return `${major}.${minor + 1}.0`;
|
return `${major + 1}.0.0`;
|
||||||
case 'patch': return `${major}.${minor}.${patch + 1}`;
|
}
|
||||||
default: return currentVersion;
|
case 'minor': {
|
||||||
|
return `${major}.${minor + 1}.0`;
|
||||||
|
}
|
||||||
|
case 'patch': {
|
||||||
|
return `${major}.${minor}.${patch + 1}`;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return currentVersion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,11 +53,11 @@ async function updateVersion() {
|
||||||
const packsDir = path.join(__dirname, '..', 'expansion-packs');
|
const packsDir = path.join(__dirname, '..', 'expansion-packs');
|
||||||
const entries = fs.readdirSync(packsDir, { withFileTypes: true });
|
const entries = fs.readdirSync(packsDir, { withFileTypes: true });
|
||||||
|
|
||||||
entries.forEach(entry => {
|
for (const entry of entries) {
|
||||||
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
||||||
console.log(` - ${entry.name}`);
|
console.log(` - ${entry.name}`);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -72,8 +78,9 @@ async function updateVersion() {
|
||||||
console.log(`\n✓ Successfully bumped ${packId} with ${bumpType} version bump`);
|
console.log(`\n✓ Successfully bumped ${packId} with ${bumpType} version bump`);
|
||||||
console.log('\nNext steps:');
|
console.log('\nNext steps:');
|
||||||
console.log(`1. Test the changes`);
|
console.log(`1. Test the changes`);
|
||||||
console.log(`2. Commit: git add -A && git commit -m "chore: bump ${packId} version (${bumpType})"`);
|
console.log(
|
||||||
|
`2. Commit: git add -A && git commit -m "chore: bump ${packId} version (${bumpType})"`,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating version:', error.message);
|
console.error('Error updating version:', error.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
|
||||||
14
tools/cli.js
14
tools/cli.js
|
|
@ -1,10 +1,8 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const { Command } = require('commander');
|
const { Command } = require('commander');
|
||||||
const WebBuilder = require('./builders/web-builder');
|
const WebBuilder = require('./builders/web-builder');
|
||||||
const V3ToV4Upgrader = require('./upgraders/v3-to-v4-upgrader');
|
const V3ToV4Upgrader = require('./upgraders/v3-to-v4-upgrader');
|
||||||
const IdeSetup = require('./installer/lib/ide-setup');
|
const IdeSetup = require('./installer/lib/ide-setup');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
|
|
||||||
const program = new Command();
|
const program = new Command();
|
||||||
|
|
||||||
|
|
@ -23,7 +21,7 @@ program
|
||||||
.option('--no-clean', 'Skip cleaning output directories')
|
.option('--no-clean', 'Skip cleaning output directories')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const builder = new WebBuilder({
|
const builder = new WebBuilder({
|
||||||
rootDir: process.cwd()
|
rootDir: process.cwd(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -66,7 +64,7 @@ program
|
||||||
.option('--no-clean', 'Skip cleaning output directories')
|
.option('--no-clean', 'Skip cleaning output directories')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const builder = new WebBuilder({
|
const builder = new WebBuilder({
|
||||||
rootDir: process.cwd()
|
rootDir: process.cwd(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -92,7 +90,7 @@ program
|
||||||
const builder = new WebBuilder({ rootDir: process.cwd() });
|
const builder = new WebBuilder({ rootDir: process.cwd() });
|
||||||
const agents = await builder.resolver.listAgents();
|
const agents = await builder.resolver.listAgents();
|
||||||
console.log('Available agents:');
|
console.log('Available agents:');
|
||||||
agents.forEach(agent => console.log(` - ${agent}`));
|
for (const agent of agents) console.log(` - ${agent}`);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -103,7 +101,7 @@ program
|
||||||
const builder = new WebBuilder({ rootDir: process.cwd() });
|
const builder = new WebBuilder({ rootDir: process.cwd() });
|
||||||
const expansions = await builder.listExpansionPacks();
|
const expansions = await builder.listExpansionPacks();
|
||||||
console.log('Available expansion packs:');
|
console.log('Available expansion packs:');
|
||||||
expansions.forEach(expansion => console.log(` - ${expansion}`));
|
for (const expansion of expansions) console.log(` - ${expansion}`);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -147,7 +145,7 @@ program
|
||||||
await upgrader.upgrade({
|
await upgrader.upgrade({
|
||||||
projectPath: options.project,
|
projectPath: options.project,
|
||||||
dryRun: options.dryRun,
|
dryRun: options.dryRun,
|
||||||
backup: options.backup
|
backup: options.backup,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const os = require("node:os");
|
const os = require('node:os');
|
||||||
const { isBinaryFile } = require("./binary.js");
|
const { isBinaryFile } = require('./binary.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregate file contents with bounded concurrency.
|
* Aggregate file contents with bounded concurrency.
|
||||||
|
|
@ -22,7 +22,7 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
|
||||||
// Automatic concurrency selection based on CPU count and workload size.
|
// Automatic concurrency selection based on CPU count and workload size.
|
||||||
// - Base on 2x logical CPUs, clamped to [2, 64]
|
// - Base on 2x logical CPUs, clamped to [2, 64]
|
||||||
// - For very small workloads, avoid excessive parallelism
|
// - For very small workloads, avoid excessive parallelism
|
||||||
const cpuCount = (os.cpus && Array.isArray(os.cpus()) ? os.cpus().length : (os.cpus?.length || 4));
|
const cpuCount = os.cpus && Array.isArray(os.cpus()) ? os.cpus().length : os.cpus?.length || 4;
|
||||||
let concurrency = Math.min(64, Math.max(2, (Number(cpuCount) || 4) * 2));
|
let concurrency = Math.min(64, Math.max(2, (Number(cpuCount) || 4) * 2));
|
||||||
if (files.length > 0 && files.length < concurrency) {
|
if (files.length > 0 && files.length < concurrency) {
|
||||||
concurrency = Math.max(1, Math.min(concurrency, Math.ceil(files.length / 2)));
|
concurrency = Math.max(1, Math.min(concurrency, Math.ceil(files.length / 2)));
|
||||||
|
|
@ -37,16 +37,16 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
|
||||||
|
|
||||||
const binary = await isBinaryFile(filePath);
|
const binary = await isBinaryFile(filePath);
|
||||||
if (binary) {
|
if (binary) {
|
||||||
const size = (await fs.stat(filePath)).size;
|
const { size } = await fs.stat(filePath);
|
||||||
results.binaryFiles.push({ path: relativePath, absolutePath: filePath, size });
|
results.binaryFiles.push({ path: relativePath, absolutePath: filePath, size });
|
||||||
} else {
|
} else {
|
||||||
const content = await fs.readFile(filePath, "utf8");
|
const content = await fs.readFile(filePath, 'utf8');
|
||||||
results.textFiles.push({
|
results.textFiles.push({
|
||||||
path: relativePath,
|
path: relativePath,
|
||||||
absolutePath: filePath,
|
absolutePath: filePath,
|
||||||
content,
|
content,
|
||||||
size: content.length,
|
size: content.length,
|
||||||
lines: content.split("\n").length,
|
lines: content.split('\n').length,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -63,8 +63,8 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i += concurrency) {
|
for (let index = 0; index < files.length; index += concurrency) {
|
||||||
const slice = files.slice(i, i + concurrency);
|
const slice = files.slice(index, index + concurrency);
|
||||||
await Promise.all(slice.map(processOne));
|
await Promise.all(slice.map(processOne));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
const fsp = require("node:fs/promises");
|
const fsp = require('node:fs/promises');
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const { Buffer } = require("node:buffer");
|
const { Buffer } = require('node:buffer');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Efficiently determine if a file is binary without reading the whole file.
|
* Efficiently determine if a file is binary without reading the whole file.
|
||||||
|
|
@ -13,25 +13,54 @@ async function isBinaryFile(filePath) {
|
||||||
try {
|
try {
|
||||||
const stats = await fsp.stat(filePath);
|
const stats = await fsp.stat(filePath);
|
||||||
if (stats.isDirectory()) {
|
if (stats.isDirectory()) {
|
||||||
throw new Error("EISDIR: illegal operation on a directory");
|
throw new Error('EISDIR: illegal operation on a directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
const binaryExtensions = new Set([
|
const binaryExtensions = new Set([
|
||||||
".jpg", ".jpeg", ".png", ".gif", ".bmp", ".ico", ".svg",
|
'.jpg',
|
||||||
".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
|
'.jpeg',
|
||||||
".zip", ".tar", ".gz", ".rar", ".7z",
|
'.png',
|
||||||
".exe", ".dll", ".so", ".dylib",
|
'.gif',
|
||||||
".mp3", ".mp4", ".avi", ".mov", ".wav",
|
'.bmp',
|
||||||
".ttf", ".otf", ".woff", ".woff2",
|
'.ico',
|
||||||
".bin", ".dat", ".db", ".sqlite",
|
'.svg',
|
||||||
|
'.pdf',
|
||||||
|
'.doc',
|
||||||
|
'.docx',
|
||||||
|
'.xls',
|
||||||
|
'.xlsx',
|
||||||
|
'.ppt',
|
||||||
|
'.pptx',
|
||||||
|
'.zip',
|
||||||
|
'.tar',
|
||||||
|
'.gz',
|
||||||
|
'.rar',
|
||||||
|
'.7z',
|
||||||
|
'.exe',
|
||||||
|
'.dll',
|
||||||
|
'.so',
|
||||||
|
'.dylib',
|
||||||
|
'.mp3',
|
||||||
|
'.mp4',
|
||||||
|
'.avi',
|
||||||
|
'.mov',
|
||||||
|
'.wav',
|
||||||
|
'.ttf',
|
||||||
|
'.otf',
|
||||||
|
'.woff',
|
||||||
|
'.woff2',
|
||||||
|
'.bin',
|
||||||
|
'.dat',
|
||||||
|
'.db',
|
||||||
|
'.sqlite',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const ext = path.extname(filePath).toLowerCase();
|
const extension = path.extname(filePath).toLowerCase();
|
||||||
if (binaryExtensions.has(ext)) return true;
|
if (binaryExtensions.has(extension)) return true;
|
||||||
if (stats.size === 0) return false;
|
if (stats.size === 0) return false;
|
||||||
|
|
||||||
const sampleSize = Math.min(4096, stats.size);
|
const sampleSize = Math.min(4096, stats.size);
|
||||||
const fd = await fsp.open(filePath, "r");
|
const fd = await fsp.open(filePath, 'r');
|
||||||
try {
|
try {
|
||||||
const buffer = Buffer.allocUnsafe(sampleSize);
|
const buffer = Buffer.allocUnsafe(sampleSize);
|
||||||
const { bytesRead } = await fd.read(buffer, 0, sampleSize, 0);
|
const { bytesRead } = await fd.read(buffer, 0, sampleSize, 0);
|
||||||
|
|
@ -41,9 +70,7 @@ async function isBinaryFile(filePath) {
|
||||||
await fd.close();
|
await fd.close();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(
|
console.warn(`Warning: Could not determine if file is binary: ${filePath} - ${error.message}`);
|
||||||
`Warning: Could not determine if file is binary: ${filePath} - ${error.message}`,
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const { execFile } = require("node:child_process");
|
const { execFile } = require('node:child_process');
|
||||||
const { promisify } = require("node:util");
|
const { promisify } = require('node:util');
|
||||||
const { glob } = require("glob");
|
const { glob } = require('glob');
|
||||||
const { loadIgnore } = require("./ignoreRules.js");
|
const { loadIgnore } = require('./ignoreRules.js');
|
||||||
|
|
||||||
const pExecFile = promisify(execFile);
|
const pExecFile = promisify(execFile);
|
||||||
|
|
||||||
async function isGitRepo(rootDir) {
|
async function isGitRepo(rootDir) {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await pExecFile("git", [
|
const { stdout } = await pExecFile('git', ['rev-parse', '--is-inside-work-tree'], {
|
||||||
"rev-parse",
|
cwd: rootDir,
|
||||||
"--is-inside-work-tree",
|
});
|
||||||
], { cwd: rootDir });
|
return (
|
||||||
return String(stdout || "").toString().trim() === "true";
|
String(stdout || '')
|
||||||
|
.toString()
|
||||||
|
.trim() === 'true'
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -20,12 +23,10 @@ async function isGitRepo(rootDir) {
|
||||||
|
|
||||||
async function gitListFiles(rootDir) {
|
async function gitListFiles(rootDir) {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await pExecFile("git", [
|
const { stdout } = await pExecFile('git', ['ls-files', '-co', '--exclude-standard'], {
|
||||||
"ls-files",
|
cwd: rootDir,
|
||||||
"-co",
|
});
|
||||||
"--exclude-standard",
|
return String(stdout || '')
|
||||||
], { cwd: rootDir });
|
|
||||||
return String(stdout || "")
|
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
.map((s) => s.trim())
|
.map((s) => s.trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
@ -48,14 +49,14 @@ async function discoverFiles(rootDir, options = {}) {
|
||||||
const { filter } = await loadIgnore(rootDir);
|
const { filter } = await loadIgnore(rootDir);
|
||||||
|
|
||||||
// Try git first
|
// Try git first
|
||||||
if (preferGit && await isGitRepo(rootDir)) {
|
if (preferGit && (await isGitRepo(rootDir))) {
|
||||||
const relFiles = await gitListFiles(rootDir);
|
const relFiles = await gitListFiles(rootDir);
|
||||||
const filteredRel = relFiles.filter((p) => filter(p));
|
const filteredRel = relFiles.filter((p) => filter(p));
|
||||||
return filteredRel.map((p) => path.resolve(rootDir, p));
|
return filteredRel.map((p) => path.resolve(rootDir, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glob fallback
|
// Glob fallback
|
||||||
const globbed = await glob("**/*", {
|
const globbed = await glob('**/*', {
|
||||||
cwd: rootDir,
|
cwd: rootDir,
|
||||||
nodir: true,
|
nodir: true,
|
||||||
dot: true,
|
dot: true,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const discovery = require("./discovery.js");
|
const discovery = require('./discovery.js');
|
||||||
const ignoreRules = require("./ignoreRules.js");
|
const ignoreRules = require('./ignoreRules.js');
|
||||||
const { isBinaryFile } = require("./binary.js");
|
const { isBinaryFile } = require('./binary.js');
|
||||||
const { aggregateFileContents } = require("./aggregate.js");
|
const { aggregateFileContents } = require('./aggregate.js');
|
||||||
|
|
||||||
// Backward-compatible signature; delegate to central loader
|
// Backward-compatible signature; delegate to central loader
|
||||||
async function parseGitignore(gitignorePath) {
|
async function parseGitignore(gitignorePath) {
|
||||||
|
|
@ -14,7 +14,7 @@ async function discoverFiles(rootDir) {
|
||||||
// Delegate to discovery module which respects .gitignore and defaults
|
// Delegate to discovery module which respects .gitignore and defaults
|
||||||
return await discovery.discoverFiles(rootDir, { preferGit: true });
|
return await discovery.discoverFiles(rootDir, { preferGit: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error discovering files:", error.message);
|
console.error('Error discovering files:', error.message);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,147 +1,147 @@
|
||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const ignore = require("ignore");
|
const ignore = require('ignore');
|
||||||
|
|
||||||
// Central default ignore patterns for discovery and filtering.
|
// Central default ignore patterns for discovery and filtering.
|
||||||
// These complement .gitignore and are applied regardless of VCS presence.
|
// These complement .gitignore and are applied regardless of VCS presence.
|
||||||
const DEFAULT_PATTERNS = [
|
const DEFAULT_PATTERNS = [
|
||||||
// Project/VCS
|
// Project/VCS
|
||||||
"**/.bmad-core/**",
|
'**/.bmad-core/**',
|
||||||
"**/.git/**",
|
'**/.git/**',
|
||||||
"**/.svn/**",
|
'**/.svn/**',
|
||||||
"**/.hg/**",
|
'**/.hg/**',
|
||||||
"**/.bzr/**",
|
'**/.bzr/**',
|
||||||
// Package/build outputs
|
// Package/build outputs
|
||||||
"**/node_modules/**",
|
'**/node_modules/**',
|
||||||
"**/bower_components/**",
|
'**/bower_components/**',
|
||||||
"**/vendor/**",
|
'**/vendor/**',
|
||||||
"**/packages/**",
|
'**/packages/**',
|
||||||
"**/build/**",
|
'**/build/**',
|
||||||
"**/dist/**",
|
'**/dist/**',
|
||||||
"**/out/**",
|
'**/out/**',
|
||||||
"**/target/**",
|
'**/target/**',
|
||||||
"**/bin/**",
|
'**/bin/**',
|
||||||
"**/obj/**",
|
'**/obj/**',
|
||||||
"**/release/**",
|
'**/release/**',
|
||||||
"**/debug/**",
|
'**/debug/**',
|
||||||
// Environments
|
// Environments
|
||||||
"**/.venv/**",
|
'**/.venv/**',
|
||||||
"**/venv/**",
|
'**/venv/**',
|
||||||
"**/.virtualenv/**",
|
'**/.virtualenv/**',
|
||||||
"**/virtualenv/**",
|
'**/virtualenv/**',
|
||||||
"**/env/**",
|
'**/env/**',
|
||||||
// Logs & coverage
|
// Logs & coverage
|
||||||
"**/*.log",
|
'**/*.log',
|
||||||
"**/npm-debug.log*",
|
'**/npm-debug.log*',
|
||||||
"**/yarn-debug.log*",
|
'**/yarn-debug.log*',
|
||||||
"**/yarn-error.log*",
|
'**/yarn-error.log*',
|
||||||
"**/lerna-debug.log*",
|
'**/lerna-debug.log*',
|
||||||
"**/coverage/**",
|
'**/coverage/**',
|
||||||
"**/.nyc_output/**",
|
'**/.nyc_output/**',
|
||||||
"**/.coverage/**",
|
'**/.coverage/**',
|
||||||
"**/test-results/**",
|
'**/test-results/**',
|
||||||
// Caches & temp
|
// Caches & temp
|
||||||
"**/.cache/**",
|
'**/.cache/**',
|
||||||
"**/.tmp/**",
|
'**/.tmp/**',
|
||||||
"**/.temp/**",
|
'**/.temp/**',
|
||||||
"**/tmp/**",
|
'**/tmp/**',
|
||||||
"**/temp/**",
|
'**/temp/**',
|
||||||
"**/.sass-cache/**",
|
'**/.sass-cache/**',
|
||||||
// IDE/editor
|
// IDE/editor
|
||||||
"**/.vscode/**",
|
'**/.vscode/**',
|
||||||
"**/.idea/**",
|
'**/.idea/**',
|
||||||
"**/*.swp",
|
'**/*.swp',
|
||||||
"**/*.swo",
|
'**/*.swo',
|
||||||
"**/*~",
|
'**/*~',
|
||||||
"**/.project",
|
'**/.project',
|
||||||
"**/.classpath",
|
'**/.classpath',
|
||||||
"**/.settings/**",
|
'**/.settings/**',
|
||||||
"**/*.sublime-project",
|
'**/*.sublime-project',
|
||||||
"**/*.sublime-workspace",
|
'**/*.sublime-workspace',
|
||||||
// Lockfiles
|
// Lockfiles
|
||||||
"**/package-lock.json",
|
'**/package-lock.json',
|
||||||
"**/yarn.lock",
|
'**/yarn.lock',
|
||||||
"**/pnpm-lock.yaml",
|
'**/pnpm-lock.yaml',
|
||||||
"**/composer.lock",
|
'**/composer.lock',
|
||||||
"**/Pipfile.lock",
|
'**/Pipfile.lock',
|
||||||
// Python/Java/compiled artifacts
|
// Python/Java/compiled artifacts
|
||||||
"**/*.pyc",
|
'**/*.pyc',
|
||||||
"**/*.pyo",
|
'**/*.pyo',
|
||||||
"**/*.pyd",
|
'**/*.pyd',
|
||||||
"**/__pycache__/**",
|
'**/__pycache__/**',
|
||||||
"**/*.class",
|
'**/*.class',
|
||||||
"**/*.jar",
|
'**/*.jar',
|
||||||
"**/*.war",
|
'**/*.war',
|
||||||
"**/*.ear",
|
'**/*.ear',
|
||||||
"**/*.o",
|
'**/*.o',
|
||||||
"**/*.so",
|
'**/*.so',
|
||||||
"**/*.dll",
|
'**/*.dll',
|
||||||
"**/*.exe",
|
'**/*.exe',
|
||||||
// System junk
|
// System junk
|
||||||
"**/lib64/**",
|
'**/lib64/**',
|
||||||
"**/.venv/lib64/**",
|
'**/.venv/lib64/**',
|
||||||
"**/venv/lib64/**",
|
'**/venv/lib64/**',
|
||||||
"**/_site/**",
|
'**/_site/**',
|
||||||
"**/.jekyll-cache/**",
|
'**/.jekyll-cache/**',
|
||||||
"**/.jekyll-metadata",
|
'**/.jekyll-metadata',
|
||||||
"**/.DS_Store",
|
'**/.DS_Store',
|
||||||
"**/.DS_Store?",
|
'**/.DS_Store?',
|
||||||
"**/._*",
|
'**/._*',
|
||||||
"**/.Spotlight-V100/**",
|
'**/.Spotlight-V100/**',
|
||||||
"**/.Trashes/**",
|
'**/.Trashes/**',
|
||||||
"**/ehthumbs.db",
|
'**/ehthumbs.db',
|
||||||
"**/Thumbs.db",
|
'**/Thumbs.db',
|
||||||
"**/desktop.ini",
|
'**/desktop.ini',
|
||||||
// XML outputs
|
// XML outputs
|
||||||
"**/flattened-codebase.xml",
|
'**/flattened-codebase.xml',
|
||||||
"**/repomix-output.xml",
|
'**/repomix-output.xml',
|
||||||
// Images, media, fonts, archives, docs, dylibs
|
// Images, media, fonts, archives, docs, dylibs
|
||||||
"**/*.jpg",
|
'**/*.jpg',
|
||||||
"**/*.jpeg",
|
'**/*.jpeg',
|
||||||
"**/*.png",
|
'**/*.png',
|
||||||
"**/*.gif",
|
'**/*.gif',
|
||||||
"**/*.bmp",
|
'**/*.bmp',
|
||||||
"**/*.ico",
|
'**/*.ico',
|
||||||
"**/*.svg",
|
'**/*.svg',
|
||||||
"**/*.pdf",
|
'**/*.pdf',
|
||||||
"**/*.doc",
|
'**/*.doc',
|
||||||
"**/*.docx",
|
'**/*.docx',
|
||||||
"**/*.xls",
|
'**/*.xls',
|
||||||
"**/*.xlsx",
|
'**/*.xlsx',
|
||||||
"**/*.ppt",
|
'**/*.ppt',
|
||||||
"**/*.pptx",
|
'**/*.pptx',
|
||||||
"**/*.zip",
|
'**/*.zip',
|
||||||
"**/*.tar",
|
'**/*.tar',
|
||||||
"**/*.gz",
|
'**/*.gz',
|
||||||
"**/*.rar",
|
'**/*.rar',
|
||||||
"**/*.7z",
|
'**/*.7z',
|
||||||
"**/*.dylib",
|
'**/*.dylib',
|
||||||
"**/*.mp3",
|
'**/*.mp3',
|
||||||
"**/*.mp4",
|
'**/*.mp4',
|
||||||
"**/*.avi",
|
'**/*.avi',
|
||||||
"**/*.mov",
|
'**/*.mov',
|
||||||
"**/*.wav",
|
'**/*.wav',
|
||||||
"**/*.ttf",
|
'**/*.ttf',
|
||||||
"**/*.otf",
|
'**/*.otf',
|
||||||
"**/*.woff",
|
'**/*.woff',
|
||||||
"**/*.woff2",
|
'**/*.woff2',
|
||||||
// Env files
|
// Env files
|
||||||
"**/.env",
|
'**/.env',
|
||||||
"**/.env.*",
|
'**/.env.*',
|
||||||
"**/*.env",
|
'**/*.env',
|
||||||
// Misc
|
// Misc
|
||||||
"**/junit.xml",
|
'**/junit.xml',
|
||||||
];
|
];
|
||||||
|
|
||||||
async function readIgnoreFile(filePath) {
|
async function readIgnoreFile(filePath) {
|
||||||
try {
|
try {
|
||||||
if (!await fs.pathExists(filePath)) return [];
|
if (!(await fs.pathExists(filePath))) return [];
|
||||||
const content = await fs.readFile(filePath, "utf8");
|
const content = await fs.readFile(filePath, 'utf8');
|
||||||
return content
|
return content
|
||||||
.split("\n")
|
.split('\n')
|
||||||
.map((l) => l.trim())
|
.map((l) => l.trim())
|
||||||
.filter((l) => l && !l.startsWith("#"));
|
.filter((l) => l && !l.startsWith('#'));
|
||||||
} catch (err) {
|
} catch {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,18 +153,18 @@ async function parseGitignore(gitignorePath) {
|
||||||
|
|
||||||
async function loadIgnore(rootDir, extraPatterns = []) {
|
async function loadIgnore(rootDir, extraPatterns = []) {
|
||||||
const ig = ignore();
|
const ig = ignore();
|
||||||
const gitignorePath = path.join(rootDir, ".gitignore");
|
const gitignorePath = path.join(rootDir, '.gitignore');
|
||||||
const patterns = [
|
const patterns = [
|
||||||
...await readIgnoreFile(gitignorePath),
|
...(await readIgnoreFile(gitignorePath)),
|
||||||
...DEFAULT_PATTERNS,
|
...DEFAULT_PATTERNS,
|
||||||
...extraPatterns,
|
...extraPatterns,
|
||||||
];
|
];
|
||||||
// De-duplicate
|
// De-duplicate
|
||||||
const unique = Array.from(new Set(patterns.map((p) => String(p))));
|
const unique = [...new Set(patterns.map(String))];
|
||||||
ig.add(unique);
|
ig.add(unique);
|
||||||
|
|
||||||
// Include-only filter: return true if path should be included
|
// Include-only filter: return true if path should be included
|
||||||
const filter = (relativePath) => !ig.ignores(relativePath.replace(/\\/g, "/"));
|
const filter = (relativePath) => !ig.ignores(relativePath.replaceAll('\\', '/'));
|
||||||
|
|
||||||
return { ig, filter, patterns: unique };
|
return { ig, filter, patterns: unique };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,14 @@
|
||||||
#!/usr/bin/env node
|
const { Command } = require('commander');
|
||||||
|
const fs = require('fs-extra');
|
||||||
const { Command } = require("commander");
|
const path = require('node:path');
|
||||||
const fs = require("fs-extra");
|
const process = require('node:process');
|
||||||
const path = require("node:path");
|
|
||||||
const process = require("node:process");
|
|
||||||
|
|
||||||
// Modularized components
|
// Modularized components
|
||||||
const { findProjectRoot } = require("./projectRoot.js");
|
const { findProjectRoot } = require('./projectRoot.js');
|
||||||
const { promptYesNo, promptPath } = require("./prompts.js");
|
const { promptYesNo, promptPath } = require('./prompts.js');
|
||||||
const {
|
const { discoverFiles, filterFiles, aggregateFileContents } = require('./files.js');
|
||||||
discoverFiles,
|
const { generateXMLOutput } = require('./xml.js');
|
||||||
filterFiles,
|
const { calculateStatistics } = require('./stats.js');
|
||||||
aggregateFileContents,
|
|
||||||
} = require("./files.js");
|
|
||||||
const { generateXMLOutput } = require("./xml.js");
|
|
||||||
const { calculateStatistics } = require("./stats.js");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively discover all files in a directory
|
* Recursively discover all files in a directory
|
||||||
|
|
@ -73,30 +67,30 @@ const { calculateStatistics } = require("./stats.js");
|
||||||
const program = new Command();
|
const program = new Command();
|
||||||
|
|
||||||
program
|
program
|
||||||
.name("bmad-flatten")
|
.name('bmad-flatten')
|
||||||
.description("BMad-Method codebase flattener tool")
|
.description('BMad-Method codebase flattener tool')
|
||||||
.version("1.0.0")
|
.version('1.0.0')
|
||||||
.option("-i, --input <path>", "Input directory to flatten", process.cwd())
|
.option('-i, --input <path>', 'Input directory to flatten', process.cwd())
|
||||||
.option("-o, --output <path>", "Output file path", "flattened-codebase.xml")
|
.option('-o, --output <path>', 'Output file path', 'flattened-codebase.xml')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
let inputDir = path.resolve(options.input);
|
let inputDir = path.resolve(options.input);
|
||||||
let outputPath = path.resolve(options.output);
|
let outputPath = path.resolve(options.output);
|
||||||
|
|
||||||
// Detect if user explicitly provided -i/--input or -o/--output
|
// Detect if user explicitly provided -i/--input or -o/--output
|
||||||
const argv = process.argv.slice(2);
|
const argv = process.argv.slice(2);
|
||||||
const userSpecifiedInput = argv.some((a) =>
|
const userSpecifiedInput = argv.some(
|
||||||
a === "-i" || a === "--input" || a.startsWith("--input=")
|
(a) => a === '-i' || a === '--input' || a.startsWith('--input='),
|
||||||
);
|
);
|
||||||
const userSpecifiedOutput = argv.some((a) =>
|
const userSpecifiedOutput = argv.some(
|
||||||
a === "-o" || a === "--output" || a.startsWith("--output=")
|
(a) => a === '-o' || a === '--output' || a.startsWith('--output='),
|
||||||
);
|
);
|
||||||
const noPathArgs = !userSpecifiedInput && !userSpecifiedOutput;
|
const noPathArguments = !userSpecifiedInput && !userSpecifiedOutput;
|
||||||
|
|
||||||
if (noPathArgs) {
|
if (noPathArguments) {
|
||||||
const detectedRoot = await findProjectRoot(process.cwd());
|
const detectedRoot = await findProjectRoot(process.cwd());
|
||||||
const suggestedOutput = detectedRoot
|
const suggestedOutput = detectedRoot
|
||||||
? path.join(detectedRoot, "flattened-codebase.xml")
|
? path.join(detectedRoot, 'flattened-codebase.xml')
|
||||||
: path.resolve("flattened-codebase.xml");
|
: path.resolve('flattened-codebase.xml');
|
||||||
|
|
||||||
if (detectedRoot) {
|
if (detectedRoot) {
|
||||||
const useDefaults = await promptYesNo(
|
const useDefaults = await promptYesNo(
|
||||||
|
|
@ -107,29 +101,23 @@ program
|
||||||
inputDir = detectedRoot;
|
inputDir = detectedRoot;
|
||||||
outputPath = suggestedOutput;
|
outputPath = suggestedOutput;
|
||||||
} else {
|
} else {
|
||||||
inputDir = await promptPath(
|
inputDir = await promptPath('Enter input directory path', process.cwd());
|
||||||
"Enter input directory path",
|
|
||||||
process.cwd(),
|
|
||||||
);
|
|
||||||
outputPath = await promptPath(
|
outputPath = await promptPath(
|
||||||
"Enter output file path",
|
'Enter output file path',
|
||||||
path.join(inputDir, "flattened-codebase.xml"),
|
path.join(inputDir, 'flattened-codebase.xml'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("Could not auto-detect a project root.");
|
console.log('Could not auto-detect a project root.');
|
||||||
inputDir = await promptPath(
|
inputDir = await promptPath('Enter input directory path', process.cwd());
|
||||||
"Enter input directory path",
|
|
||||||
process.cwd(),
|
|
||||||
);
|
|
||||||
outputPath = await promptPath(
|
outputPath = await promptPath(
|
||||||
"Enter output file path",
|
'Enter output file path',
|
||||||
path.join(inputDir, "flattened-codebase.xml"),
|
path.join(inputDir, 'flattened-codebase.xml'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
"Could not auto-detect a project root and no arguments were provided. Please specify -i/--input and -o/--output.",
|
'Could not auto-detect a project root and no arguments were provided. Please specify -i/--input and -o/--output.',
|
||||||
);
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -142,25 +130,23 @@ program
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Verify input directory exists
|
// Verify input directory exists
|
||||||
if (!await fs.pathExists(inputDir)) {
|
if (!(await fs.pathExists(inputDir))) {
|
||||||
console.error(`❌ Error: Input directory does not exist: ${inputDir}`);
|
console.error(`❌ Error: Input directory does not exist: ${inputDir}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import ora dynamically
|
// Import ora dynamically
|
||||||
const { default: ora } = await import("ora");
|
const { default: ora } = await import('ora');
|
||||||
|
|
||||||
// Start file discovery with spinner
|
// Start file discovery with spinner
|
||||||
const discoverySpinner = ora("🔍 Discovering files...").start();
|
const discoverySpinner = ora('🔍 Discovering files...').start();
|
||||||
const files = await discoverFiles(inputDir);
|
const files = await discoverFiles(inputDir);
|
||||||
const filteredFiles = await filterFiles(files, inputDir);
|
const filteredFiles = await filterFiles(files, inputDir);
|
||||||
discoverySpinner.succeed(
|
discoverySpinner.succeed(`📁 Found ${filteredFiles.length} files to include`);
|
||||||
`📁 Found ${filteredFiles.length} files to include`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Process files with progress tracking
|
// Process files with progress tracking
|
||||||
console.log("Reading file contents");
|
console.log('Reading file contents');
|
||||||
const processingSpinner = ora("📄 Processing files...").start();
|
const processingSpinner = ora('📄 Processing files...').start();
|
||||||
const aggregatedContent = await aggregateFileContents(
|
const aggregatedContent = await aggregateFileContents(
|
||||||
filteredFiles,
|
filteredFiles,
|
||||||
inputDir,
|
inputDir,
|
||||||
|
|
@ -178,34 +164,30 @@ program
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate XML output using streaming
|
// Generate XML output using streaming
|
||||||
const xmlSpinner = ora("🔧 Generating XML output...").start();
|
const xmlSpinner = ora('🔧 Generating XML output...').start();
|
||||||
await generateXMLOutput(aggregatedContent, outputPath);
|
await generateXMLOutput(aggregatedContent, outputPath);
|
||||||
xmlSpinner.succeed("📝 XML generation completed");
|
xmlSpinner.succeed('📝 XML generation completed');
|
||||||
|
|
||||||
// Calculate and display statistics
|
// Calculate and display statistics
|
||||||
const outputStats = await fs.stat(outputPath);
|
const outputStats = await fs.stat(outputPath);
|
||||||
const stats = calculateStatistics(aggregatedContent, outputStats.size);
|
const stats = calculateStatistics(aggregatedContent, outputStats.size);
|
||||||
|
|
||||||
// Display completion summary
|
// Display completion summary
|
||||||
console.log("\n📊 Completion Summary:");
|
console.log('\n📊 Completion Summary:');
|
||||||
console.log(
|
console.log(
|
||||||
`✅ Successfully processed ${filteredFiles.length} files into ${
|
`✅ Successfully processed ${filteredFiles.length} files into ${path.basename(outputPath)}`,
|
||||||
path.basename(outputPath)
|
|
||||||
}`,
|
|
||||||
);
|
);
|
||||||
console.log(`📁 Output file: ${outputPath}`);
|
console.log(`📁 Output file: ${outputPath}`);
|
||||||
console.log(`📏 Total source size: ${stats.totalSize}`);
|
console.log(`📏 Total source size: ${stats.totalSize}`);
|
||||||
console.log(`📄 Generated XML size: ${stats.xmlSize}`);
|
console.log(`📄 Generated XML size: ${stats.xmlSize}`);
|
||||||
console.log(
|
console.log(`📝 Total lines of code: ${stats.totalLines.toLocaleString()}`);
|
||||||
`📝 Total lines of code: ${stats.totalLines.toLocaleString()}`,
|
|
||||||
);
|
|
||||||
console.log(`🔢 Estimated tokens: ${stats.estimatedTokens}`);
|
console.log(`🔢 Estimated tokens: ${stats.estimatedTokens}`);
|
||||||
console.log(
|
console.log(
|
||||||
`📊 File breakdown: ${stats.textFiles} text, ${stats.binaryFiles} binary, ${stats.errorFiles} errors`,
|
`📊 File breakdown: ${stats.textFiles} text, ${stats.binaryFiles} binary, ${stats.errorFiles} errors`,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Critical error:", error.message);
|
console.error('❌ Critical error:', error.message);
|
||||||
console.error("An unexpected error occurred.");
|
console.error('An unexpected error occurred.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to find the project root by walking up from startDir
|
* Attempt to find the project root by walking up from startDir
|
||||||
|
|
@ -12,24 +12,22 @@ async function findProjectRoot(startDir) {
|
||||||
let dir = path.resolve(startDir);
|
let dir = path.resolve(startDir);
|
||||||
const root = path.parse(dir).root;
|
const root = path.parse(dir).root;
|
||||||
const markers = [
|
const markers = [
|
||||||
".git",
|
'.git',
|
||||||
"package.json",
|
'package.json',
|
||||||
"pnpm-workspace.yaml",
|
'pnpm-workspace.yaml',
|
||||||
"yarn.lock",
|
'yarn.lock',
|
||||||
"pnpm-lock.yaml",
|
'pnpm-lock.yaml',
|
||||||
"pyproject.toml",
|
'pyproject.toml',
|
||||||
"requirements.txt",
|
'requirements.txt',
|
||||||
"go.mod",
|
'go.mod',
|
||||||
"Cargo.toml",
|
'Cargo.toml',
|
||||||
"composer.json",
|
'composer.json',
|
||||||
".hg",
|
'.hg',
|
||||||
".svn",
|
'.svn',
|
||||||
];
|
];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const exists = await Promise.all(
|
const exists = await Promise.all(markers.map((m) => fs.pathExists(path.join(dir, m))));
|
||||||
markers.map((m) => fs.pathExists(path.join(dir, m))),
|
|
||||||
);
|
|
||||||
if (exists.some(Boolean)) {
|
if (exists.some(Boolean)) {
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
const os = require("node:os");
|
const os = require('node:os');
|
||||||
const path = require("node:path");
|
const path = require('node:path');
|
||||||
const readline = require("node:readline");
|
const readline = require('node:readline');
|
||||||
const process = require("node:process");
|
const process = require('node:process');
|
||||||
|
|
||||||
function expandHome(p) {
|
function expandHome(p) {
|
||||||
if (!p) return p;
|
if (!p) return p;
|
||||||
if (p.startsWith("~")) return path.join(os.homedir(), p.slice(1));
|
if (p.startsWith('~')) return path.join(os.homedir(), p.slice(1));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,16 +27,16 @@ function promptQuestion(question) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function promptYesNo(question, defaultYes = true) {
|
async function promptYesNo(question, defaultYes = true) {
|
||||||
const suffix = defaultYes ? " [Y/n] " : " [y/N] ";
|
const suffix = defaultYes ? ' [Y/n] ' : ' [y/N] ';
|
||||||
const ans = (await promptQuestion(`${question}${suffix}`)).trim().toLowerCase();
|
const ans = (await promptQuestion(`${question}${suffix}`)).trim().toLowerCase();
|
||||||
if (!ans) return defaultYes;
|
if (!ans) return defaultYes;
|
||||||
if (["y", "yes"].includes(ans)) return true;
|
if (['y', 'yes'].includes(ans)) return true;
|
||||||
if (["n", "no"].includes(ans)) return false;
|
if (['n', 'no'].includes(ans)) return false;
|
||||||
return promptYesNo(question, defaultYes);
|
return promptYesNo(question, defaultYes);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function promptPath(question, defaultValue) {
|
async function promptPath(question, defaultValue) {
|
||||||
const prompt = `${question}${defaultValue ? ` (default: ${defaultValue})` : ""}: `;
|
const prompt = `${question}${defaultValue ? ` (default: ${defaultValue})` : ''}: `;
|
||||||
const ans = (await promptQuestion(prompt)).trim();
|
const ans = (await promptQuestion(prompt)).trim();
|
||||||
return expandHome(ans || defaultValue);
|
return expandHome(ans || defaultValue);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,44 @@
|
||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
function escapeXml(str) {
|
function escapeXml(string_) {
|
||||||
if (typeof str !== "string") {
|
if (typeof string_ !== 'string') {
|
||||||
return String(str);
|
return String(string_);
|
||||||
}
|
}
|
||||||
return str
|
return string_.replaceAll('&', '&').replaceAll('<', '<').replaceAll("'", ''');
|
||||||
.replace(/&/g, "&")
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/'/g, "'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function indentFileContent(content) {
|
function indentFileContent(content) {
|
||||||
if (typeof content !== "string") {
|
if (typeof content !== 'string') {
|
||||||
return String(content);
|
return String(content);
|
||||||
}
|
}
|
||||||
return content.split("\n").map((line) => ` ${line}`);
|
return content.split('\n').map((line) => ` ${line}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateXMLOutput(aggregatedContent, outputPath) {
|
function generateXMLOutput(aggregatedContent, outputPath) {
|
||||||
const { textFiles } = aggregatedContent;
|
const { textFiles } = aggregatedContent;
|
||||||
const writeStream = fs.createWriteStream(outputPath, { encoding: "utf8" });
|
const writeStream = fs.createWriteStream(outputPath, { encoding: 'utf8' });
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
writeStream.on("error", reject);
|
writeStream.on('error', reject);
|
||||||
writeStream.on("finish", resolve);
|
writeStream.on('finish', resolve);
|
||||||
|
|
||||||
writeStream.write('<?xml version="1.0" encoding="UTF-8"?>\n');
|
writeStream.write('<?xml version="1.0" encoding="UTF-8"?>\n');
|
||||||
writeStream.write("<files>\n");
|
writeStream.write('<files>\n');
|
||||||
|
|
||||||
// Sort files by path for deterministic order
|
// Sort files by path for deterministic order
|
||||||
const filesSorted = [...textFiles].sort((a, b) =>
|
const filesSorted = [...textFiles].sort((a, b) => a.path.localeCompare(b.path));
|
||||||
a.path.localeCompare(b.path)
|
|
||||||
);
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
const writeNext = () => {
|
const writeNext = () => {
|
||||||
if (index >= filesSorted.length) {
|
if (index >= filesSorted.length) {
|
||||||
writeStream.write("</files>\n");
|
writeStream.write('</files>\n');
|
||||||
writeStream.end();
|
writeStream.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = filesSorted[index++];
|
const file = filesSorted[index++];
|
||||||
const p = escapeXml(file.path);
|
const p = escapeXml(file.path);
|
||||||
const content = typeof file.content === "string" ? file.content : "";
|
const content = typeof file.content === 'string' ? file.content : '';
|
||||||
|
|
||||||
if (content.length === 0) {
|
if (content.length === 0) {
|
||||||
writeStream.write(`\t<file path='${p}'/>\n`);
|
writeStream.write(`\t<file path='${p}'/>\n`);
|
||||||
|
|
@ -51,27 +46,34 @@ function generateXMLOutput(aggregatedContent, outputPath) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const needsCdata = content.includes("<") || content.includes("&") ||
|
const needsCdata = content.includes('<') || content.includes('&') || content.includes(']]>');
|
||||||
content.includes("]]>");
|
|
||||||
if (needsCdata) {
|
if (needsCdata) {
|
||||||
// Open tag and CDATA on their own line with tab indent; content lines indented with two tabs
|
// Open tag and CDATA on their own line with tab indent; content lines indented with two tabs
|
||||||
writeStream.write(`\t<file path='${p}'><![CDATA[\n`);
|
writeStream.write(`\t<file path='${p}'><![CDATA[\n`);
|
||||||
// Safely split any occurrences of "]]>" inside content, trim trailing newlines, indent each line with two tabs
|
// Safely split any occurrences of "]]>" inside content, trim trailing newlines, indent each line with two tabs
|
||||||
const safe = content.replace(/]]>/g, "]]]]><![CDATA[>");
|
const safe = content.replaceAll(']]>', ']]]]><![CDATA[>');
|
||||||
const trimmed = safe.replace(/[\r\n]+$/, "");
|
const trimmed = safe.replace(/[\r\n]+$/, '');
|
||||||
const indented = trimmed.length > 0
|
const indented =
|
||||||
? trimmed.split("\n").map((line) => `\t\t${line}`).join("\n")
|
trimmed.length > 0
|
||||||
: "";
|
? trimmed
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => `\t\t${line}`)
|
||||||
|
.join('\n')
|
||||||
|
: '';
|
||||||
writeStream.write(indented);
|
writeStream.write(indented);
|
||||||
// Close CDATA and attach closing tag directly after the last content line
|
// Close CDATA and attach closing tag directly after the last content line
|
||||||
writeStream.write("]]></file>\n");
|
writeStream.write(']]></file>\n');
|
||||||
} else {
|
} else {
|
||||||
// Write opening tag then newline; indent content with two tabs; attach closing tag directly after last content char
|
// Write opening tag then newline; indent content with two tabs; attach closing tag directly after last content char
|
||||||
writeStream.write(`\t<file path='${p}'>\n`);
|
writeStream.write(`\t<file path='${p}'>\n`);
|
||||||
const trimmed = content.replace(/[\r\n]+$/, "");
|
const trimmed = content.replace(/[\r\n]+$/, '');
|
||||||
const indented = trimmed.length > 0
|
const indented =
|
||||||
? trimmed.split("\n").map((line) => `\t\t${line}`).join("\n")
|
trimmed.length > 0
|
||||||
: "";
|
? trimmed
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => `\t\t${line}`)
|
||||||
|
.join('\n')
|
||||||
|
: '';
|
||||||
writeStream.write(indented);
|
writeStream.write(indented);
|
||||||
writeStream.write(`</file>\n`);
|
writeStream.write(`</file>\n`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const { program } = require('commander');
|
const { program } = require('commander');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
const fs = require('fs').promises;
|
const fs = require('node:fs').promises;
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const inquirer = require('inquirer');
|
const inquirer = require('inquirer');
|
||||||
|
|
@ -14,18 +14,20 @@ try {
|
||||||
// Try installer context first (when run from tools/installer/)
|
// Try installer context first (when run from tools/installer/)
|
||||||
version = require('../package.json').version;
|
version = require('../package.json').version;
|
||||||
installer = require('../lib/installer');
|
installer = require('../lib/installer');
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
// Fall back to root context (when run via npx from GitHub)
|
// Fall back to root context (when run via npx from GitHub)
|
||||||
console.log(`Installer context not found (${e.message}), trying root context...`);
|
console.log(`Installer context not found (${error.message}), trying root context...`);
|
||||||
try {
|
try {
|
||||||
version = require('../../../package.json').version;
|
version = require('../../../package.json').version;
|
||||||
installer = require('../../../tools/installer/lib/installer');
|
installer = require('../../../tools/installer/lib/installer');
|
||||||
} catch (e2) {
|
} catch (error) {
|
||||||
console.error('Error: Could not load required modules. Please ensure you are running from the correct directory.');
|
console.error(
|
||||||
|
'Error: Could not load required modules. Please ensure you are running from the correct directory.',
|
||||||
|
);
|
||||||
console.error('Debug info:', {
|
console.error('Debug info:', {
|
||||||
__dirname,
|
__dirname,
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
error: e2.message
|
error: error.message,
|
||||||
});
|
});
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -41,8 +43,14 @@ program
|
||||||
.option('-f, --full', 'Install complete BMad Method')
|
.option('-f, --full', 'Install complete BMad Method')
|
||||||
.option('-x, --expansion-only', 'Install only expansion packs (no bmad-core)')
|
.option('-x, --expansion-only', 'Install only expansion packs (no bmad-core)')
|
||||||
.option('-d, --directory <path>', 'Installation directory')
|
.option('-d, --directory <path>', 'Installation directory')
|
||||||
.option('-i, --ide <ide...>', 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, other)')
|
.option(
|
||||||
.option('-e, --expansion-packs <packs...>', 'Install specific expansion packs (can specify multiple)')
|
'-i, --ide <ide...>',
|
||||||
|
'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, other)',
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'-e, --expansion-packs <packs...>',
|
||||||
|
'Install specific expansion packs (can specify multiple)',
|
||||||
|
)
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
try {
|
try {
|
||||||
if (!options.full && !options.expansionOnly) {
|
if (!options.full && !options.expansionOnly) {
|
||||||
|
|
@ -60,8 +68,8 @@ program
|
||||||
const config = {
|
const config = {
|
||||||
installType,
|
installType,
|
||||||
directory: options.directory || '.',
|
directory: options.directory || '.',
|
||||||
ides: (options.ide || []).filter(ide => ide !== 'other'),
|
ides: (options.ide || []).filter((ide) => ide !== 'other'),
|
||||||
expansionPacks: options.expansionPacks || []
|
expansionPacks: options.expansionPacks || [],
|
||||||
};
|
};
|
||||||
await installer.install(config);
|
await installer.install(config);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
@ -125,16 +133,17 @@ program
|
||||||
});
|
});
|
||||||
|
|
||||||
async function promptInstallation() {
|
async function promptInstallation() {
|
||||||
|
|
||||||
// Display ASCII logo
|
// Display ASCII logo
|
||||||
console.log(chalk.bold.cyan(`
|
console.log(
|
||||||
|
chalk.bold.cyan(`
|
||||||
██████╗ ███╗ ███╗ █████╗ ██████╗ ███╗ ███╗███████╗████████╗██╗ ██╗ ██████╗ ██████╗
|
██████╗ ███╗ ███╗ █████╗ ██████╗ ███╗ ███╗███████╗████████╗██╗ ██╗ ██████╗ ██████╗
|
||||||
██╔══██╗████╗ ████║██╔══██╗██╔══██╗ ████╗ ████║██╔════╝╚══██╔══╝██║ ██║██╔═══██╗██╔══██╗
|
██╔══██╗████╗ ████║██╔══██╗██╔══██╗ ████╗ ████║██╔════╝╚══██╔══╝██║ ██║██╔═══██╗██╔══██╗
|
||||||
██████╔╝██╔████╔██║███████║██║ ██║█████╗██╔████╔██║█████╗ ██║ ███████║██║ ██║██║ ██║
|
██████╔╝██╔████╔██║███████║██║ ██║█████╗██╔████╔██║█████╗ ██║ ███████║██║ ██║██║ ██║
|
||||||
██╔══██╗██║╚██╔╝██║██╔══██║██║ ██║╚════╝██║╚██╔╝██║██╔══╝ ██║ ██╔══██║██║ ██║██║ ██║
|
██╔══██╗██║╚██╔╝██║██╔══██║██║ ██║╚════╝██║╚██╔╝██║██╔══╝ ██║ ██╔══██║██║ ██║██║ ██║
|
||||||
██████╔╝██║ ╚═╝ ██║██║ ██║██████╔╝ ██║ ╚═╝ ██║███████╗ ██║ ██║ ██║╚██████╔╝██████╔╝
|
██████╔╝██║ ╚═╝ ██║██║ ██║██████╔╝ ██║ ╚═╝ ██║███████╗ ██║ ██║ ██║╚██████╔╝██████╔╝
|
||||||
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝
|
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝
|
||||||
`));
|
`),
|
||||||
|
);
|
||||||
|
|
||||||
console.log(chalk.bold.magenta('🚀 Universal AI Agent Framework for Any Domain'));
|
console.log(chalk.bold.magenta('🚀 Universal AI Agent Framework for Any Domain'));
|
||||||
console.log(chalk.bold.blue(`✨ Installer v${version}\n`));
|
console.log(chalk.bold.blue(`✨ Installer v${version}\n`));
|
||||||
|
|
@ -152,8 +161,8 @@ async function promptInstallation() {
|
||||||
return 'Please enter a valid project path';
|
return 'Please enter a valid project path';
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
answers.directory = directory;
|
answers.directory = directory;
|
||||||
|
|
||||||
|
|
@ -180,7 +189,8 @@ async function promptInstallation() {
|
||||||
if (state.type === 'v4_existing') {
|
if (state.type === 'v4_existing') {
|
||||||
const currentVersion = state.manifest?.version || 'unknown';
|
const currentVersion = state.manifest?.version || 'unknown';
|
||||||
const newVersion = version; // Always use package.json version
|
const newVersion = version; // Always use package.json version
|
||||||
const versionInfo = currentVersion === newVersion
|
const versionInfo =
|
||||||
|
currentVersion === newVersion
|
||||||
? `(v${currentVersion} - reinstall)`
|
? `(v${currentVersion} - reinstall)`
|
||||||
: `(v${currentVersion} → v${newVersion})`;
|
: `(v${currentVersion} → v${newVersion})`;
|
||||||
bmadOptionText = `Update ${coreShortTitle} ${versionInfo} .bmad-core`;
|
bmadOptionText = `Update ${coreShortTitle} ${versionInfo} .bmad-core`;
|
||||||
|
|
@ -191,7 +201,7 @@ async function promptInstallation() {
|
||||||
choices.push({
|
choices.push({
|
||||||
name: bmadOptionText,
|
name: bmadOptionText,
|
||||||
value: 'bmad-core',
|
value: 'bmad-core',
|
||||||
checked: true
|
checked: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add expansion pack options
|
// Add expansion pack options
|
||||||
|
|
@ -202,7 +212,8 @@ async function promptInstallation() {
|
||||||
if (existing) {
|
if (existing) {
|
||||||
const currentVersion = existing.manifest?.version || 'unknown';
|
const currentVersion = existing.manifest?.version || 'unknown';
|
||||||
const newVersion = pack.version;
|
const newVersion = pack.version;
|
||||||
const versionInfo = currentVersion === newVersion
|
const versionInfo =
|
||||||
|
currentVersion === newVersion
|
||||||
? `(v${currentVersion} - reinstall)`
|
? `(v${currentVersion} - reinstall)`
|
||||||
: `(v${currentVersion} → v${newVersion})`;
|
: `(v${currentVersion} → v${newVersion})`;
|
||||||
packOptionText = `Update ${pack.shortTitle} ${versionInfo} .${pack.id}`;
|
packOptionText = `Update ${pack.shortTitle} ${versionInfo} .${pack.id}`;
|
||||||
|
|
@ -213,7 +224,7 @@ async function promptInstallation() {
|
||||||
choices.push({
|
choices.push({
|
||||||
name: packOptionText,
|
name: packOptionText,
|
||||||
value: pack.id,
|
value: pack.id,
|
||||||
checked: false
|
checked: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,13 +240,13 @@ async function promptInstallation() {
|
||||||
return 'Please select at least one item to install';
|
return 'Please select at least one item to install';
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Process selections
|
// Process selections
|
||||||
answers.installType = selectedItems.includes('bmad-core') ? 'full' : 'expansion-only';
|
answers.installType = selectedItems.includes('bmad-core') ? 'full' : 'expansion-only';
|
||||||
answers.expansionPacks = selectedItems.filter(item => item !== 'bmad-core');
|
answers.expansionPacks = selectedItems.filter((item) => item !== 'bmad-core');
|
||||||
|
|
||||||
// Ask sharding questions if installing BMad core
|
// Ask sharding questions if installing BMad core
|
||||||
if (selectedItems.includes('bmad-core')) {
|
if (selectedItems.includes('bmad-core')) {
|
||||||
|
|
@ -248,8 +259,8 @@ async function promptInstallation() {
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'prdSharded',
|
name: 'prdSharded',
|
||||||
message: 'Will the PRD (Product Requirements Document) be sharded into multiple files?',
|
message: 'Will the PRD (Product Requirements Document) be sharded into multiple files?',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
answers.prdSharded = prdSharded;
|
answers.prdSharded = prdSharded;
|
||||||
|
|
||||||
|
|
@ -259,18 +270,30 @@ async function promptInstallation() {
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'architectureSharded',
|
name: 'architectureSharded',
|
||||||
message: 'Will the architecture documentation be sharded into multiple files?',
|
message: 'Will the architecture documentation be sharded into multiple files?',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
answers.architectureSharded = architectureSharded;
|
answers.architectureSharded = architectureSharded;
|
||||||
|
|
||||||
// Show warning if architecture sharding is disabled
|
// Show warning if architecture sharding is disabled
|
||||||
if (!architectureSharded) {
|
if (!architectureSharded) {
|
||||||
console.log(chalk.yellow.bold('\n⚠️ IMPORTANT: Architecture Sharding Disabled'));
|
console.log(chalk.yellow.bold('\n⚠️ IMPORTANT: Architecture Sharding Disabled'));
|
||||||
console.log(chalk.yellow('With architecture sharding disabled, you should still create the files listed'));
|
console.log(
|
||||||
console.log(chalk.yellow('in devLoadAlwaysFiles (like coding-standards.md, tech-stack.md, source-tree.md)'));
|
chalk.yellow(
|
||||||
|
'With architecture sharding disabled, you should still create the files listed',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'in devLoadAlwaysFiles (like coding-standards.md, tech-stack.md, source-tree.md)',
|
||||||
|
),
|
||||||
|
);
|
||||||
console.log(chalk.yellow('as these are used by the dev agent at runtime.'));
|
console.log(chalk.yellow('as these are used by the dev agent at runtime.'));
|
||||||
console.log(chalk.yellow('\nAlternatively, you can remove these files from the devLoadAlwaysFiles list'));
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'\nAlternatively, you can remove these files from the devLoadAlwaysFiles list',
|
||||||
|
),
|
||||||
|
);
|
||||||
console.log(chalk.yellow('in your core-config.yaml after installation.'));
|
console.log(chalk.yellow('in your core-config.yaml after installation.'));
|
||||||
|
|
||||||
const { acknowledge } = await inquirer.prompt([
|
const { acknowledge } = await inquirer.prompt([
|
||||||
|
|
@ -278,8 +301,8 @@ async function promptInstallation() {
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'acknowledge',
|
name: 'acknowledge',
|
||||||
message: 'Do you acknowledge this requirement and want to proceed?',
|
message: 'Do you acknowledge this requirement and want to proceed?',
|
||||||
default: false
|
default: false,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!acknowledge) {
|
if (!acknowledge) {
|
||||||
|
|
@ -295,7 +318,11 @@ async function promptInstallation() {
|
||||||
|
|
||||||
while (!ideSelectionComplete) {
|
while (!ideSelectionComplete) {
|
||||||
console.log(chalk.cyan('\n🛠️ IDE Configuration'));
|
console.log(chalk.cyan('\n🛠️ IDE Configuration'));
|
||||||
console.log(chalk.bold.yellow.bgRed(' ⚠️ IMPORTANT: This is a MULTISELECT! Use SPACEBAR to toggle each IDE! '));
|
console.log(
|
||||||
|
chalk.bold.yellow.bgRed(
|
||||||
|
' ⚠️ IMPORTANT: This is a MULTISELECT! Use SPACEBAR to toggle each IDE! ',
|
||||||
|
),
|
||||||
|
);
|
||||||
console.log(chalk.bold.magenta('🔸 Use arrow keys to navigate'));
|
console.log(chalk.bold.magenta('🔸 Use arrow keys to navigate'));
|
||||||
console.log(chalk.bold.magenta('🔸 Use SPACEBAR to select/deselect IDEs'));
|
console.log(chalk.bold.magenta('🔸 Use SPACEBAR to select/deselect IDEs'));
|
||||||
console.log(chalk.bold.magenta('🔸 Press ENTER when finished selecting\n'));
|
console.log(chalk.bold.magenta('🔸 Press ENTER when finished selecting\n'));
|
||||||
|
|
@ -304,7 +331,8 @@ async function promptInstallation() {
|
||||||
{
|
{
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
name: 'ides',
|
name: 'ides',
|
||||||
message: 'Which IDE(s) do you want to configure? (Select with SPACEBAR, confirm with ENTER):',
|
message:
|
||||||
|
'Which IDE(s) do you want to configure? (Select with SPACEBAR, confirm with ENTER):',
|
||||||
choices: [
|
choices: [
|
||||||
{ name: 'Cursor', value: 'cursor' },
|
{ name: 'Cursor', value: 'cursor' },
|
||||||
{ name: 'Claude Code', value: 'claude-code' },
|
{ name: 'Claude Code', value: 'claude-code' },
|
||||||
|
|
@ -315,9 +343,9 @@ async function promptInstallation() {
|
||||||
{ name: 'Cline', value: 'cline' },
|
{ name: 'Cline', value: 'cline' },
|
||||||
{ name: 'Gemini CLI', value: 'gemini' },
|
{ name: 'Gemini CLI', value: 'gemini' },
|
||||||
{ name: 'Qwen Code', value: 'qwen-code' },
|
{ name: 'Qwen Code', value: 'qwen-code' },
|
||||||
{ name: 'Github Copilot', value: 'github-copilot' }
|
{ name: 'Github Copilot', value: 'github-copilot' },
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ides = ideResponse.ides;
|
ides = ideResponse.ides;
|
||||||
|
|
@ -328,13 +356,19 @@ async function promptInstallation() {
|
||||||
{
|
{
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'confirmNoIde',
|
name: 'confirmNoIde',
|
||||||
message: chalk.red('⚠️ You have NOT selected any IDEs. This means NO IDE integration will be set up. Is this correct?'),
|
message: chalk.red(
|
||||||
default: false
|
'⚠️ You have NOT selected any IDEs. This means NO IDE integration will be set up. Is this correct?',
|
||||||
}
|
),
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!confirmNoIde) {
|
if (!confirmNoIde) {
|
||||||
console.log(chalk.bold.red('\n🔄 Returning to IDE selection. Remember to use SPACEBAR to select IDEs!\n'));
|
console.log(
|
||||||
|
chalk.bold.red(
|
||||||
|
'\n🔄 Returning to IDE selection. Remember to use SPACEBAR to select IDEs!\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
continue; // Go back to IDE selection only
|
continue; // Go back to IDE selection only
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +382,9 @@ async function promptInstallation() {
|
||||||
// Configure GitHub Copilot immediately if selected
|
// Configure GitHub Copilot immediately if selected
|
||||||
if (ides.includes('github-copilot')) {
|
if (ides.includes('github-copilot')) {
|
||||||
console.log(chalk.cyan('\n🔧 GitHub Copilot Configuration'));
|
console.log(chalk.cyan('\n🔧 GitHub Copilot Configuration'));
|
||||||
console.log(chalk.dim('BMad works best with specific VS Code settings for optimal agent experience.\n'));
|
console.log(
|
||||||
|
chalk.dim('BMad works best with specific VS Code settings for optimal agent experience.\n'),
|
||||||
|
);
|
||||||
|
|
||||||
const { configChoice } = await inquirer.prompt([
|
const { configChoice } = await inquirer.prompt([
|
||||||
{
|
{
|
||||||
|
|
@ -358,19 +394,19 @@ async function promptInstallation() {
|
||||||
choices: [
|
choices: [
|
||||||
{
|
{
|
||||||
name: 'Use recommended defaults (fastest setup)',
|
name: 'Use recommended defaults (fastest setup)',
|
||||||
value: 'defaults'
|
value: 'defaults',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Configure each setting manually (customize to your preferences)',
|
name: 'Configure each setting manually (customize to your preferences)',
|
||||||
value: 'manual'
|
value: 'manual',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Skip settings configuration (I\'ll configure manually later)',
|
name: "Skip settings configuration (I'll configure manually later)",
|
||||||
value: 'skip'
|
value: 'skip',
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
default: 'defaults'
|
default: 'defaults',
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
answers.githubCopilotConfig = { configChoice };
|
answers.githubCopilotConfig = { configChoice };
|
||||||
|
|
@ -381,14 +417,17 @@ async function promptInstallation() {
|
||||||
{
|
{
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'includeWebBundles',
|
name: 'includeWebBundles',
|
||||||
message: 'Would you like to include pre-built web bundles? (standalone files for ChatGPT, Claude, Gemini)',
|
message:
|
||||||
default: false
|
'Would you like to include pre-built web bundles? (standalone files for ChatGPT, Claude, Gemini)',
|
||||||
}
|
default: false,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (includeWebBundles) {
|
if (includeWebBundles) {
|
||||||
console.log(chalk.cyan('\n📦 Web bundles are standalone files perfect for web AI platforms.'));
|
console.log(chalk.cyan('\n📦 Web bundles are standalone files perfect for web AI platforms.'));
|
||||||
console.log(chalk.dim(' You can choose different teams/agents than your IDE installation.\n'));
|
console.log(
|
||||||
|
chalk.dim(' You can choose different teams/agents than your IDE installation.\n'),
|
||||||
|
);
|
||||||
|
|
||||||
const { webBundleType } = await inquirer.prompt([
|
const { webBundleType } = await inquirer.prompt([
|
||||||
{
|
{
|
||||||
|
|
@ -398,22 +437,22 @@ async function promptInstallation() {
|
||||||
choices: [
|
choices: [
|
||||||
{
|
{
|
||||||
name: 'All available bundles (agents, teams, expansion packs)',
|
name: 'All available bundles (agents, teams, expansion packs)',
|
||||||
value: 'all'
|
value: 'all',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Specific teams only',
|
name: 'Specific teams only',
|
||||||
value: 'teams'
|
value: 'teams',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Individual agents only',
|
name: 'Individual agents only',
|
||||||
value: 'agents'
|
value: 'agents',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Custom selection',
|
name: 'Custom selection',
|
||||||
value: 'custom'
|
value: 'custom',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
answers.webBundleType = webBundleType;
|
answers.webBundleType = webBundleType;
|
||||||
|
|
@ -426,18 +465,18 @@ async function promptInstallation() {
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
name: 'selectedTeams',
|
name: 'selectedTeams',
|
||||||
message: 'Select team bundles to include:',
|
message: 'Select team bundles to include:',
|
||||||
choices: teams.map(t => ({
|
choices: teams.map((t) => ({
|
||||||
name: `${t.icon || '📋'} ${t.name}: ${t.description}`,
|
name: `${t.icon || '📋'} ${t.name}: ${t.description}`,
|
||||||
value: t.id,
|
value: t.id,
|
||||||
checked: webBundleType === 'teams' // Check all if teams-only mode
|
checked: webBundleType === 'teams', // Check all if teams-only mode
|
||||||
})),
|
})),
|
||||||
validate: (answer) => {
|
validate: (answer) => {
|
||||||
if (answer.length < 1) {
|
if (answer.length === 0) {
|
||||||
return 'You must select at least one team.';
|
return 'You must select at least one team.';
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
answers.selectedWebBundleTeams = selectedTeams;
|
answers.selectedWebBundleTeams = selectedTeams;
|
||||||
}
|
}
|
||||||
|
|
@ -449,8 +488,8 @@ async function promptInstallation() {
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'includeIndividualAgents',
|
name: 'includeIndividualAgents',
|
||||||
message: 'Also include individual agent bundles?',
|
message: 'Also include individual agent bundles?',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
answers.includeIndividualAgents = includeIndividualAgents;
|
answers.includeIndividualAgents = includeIndividualAgents;
|
||||||
}
|
}
|
||||||
|
|
@ -466,8 +505,8 @@ async function promptInstallation() {
|
||||||
return 'Please enter a valid directory path';
|
return 'Please enter a valid directory path';
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
answers.webBundlesDirectory = webBundlesDirectory;
|
answers.webBundlesDirectory = webBundlesDirectory;
|
||||||
}
|
}
|
||||||
|
|
@ -480,6 +519,6 @@ async function promptInstallation() {
|
||||||
program.parse(process.argv);
|
program.parse(process.argv);
|
||||||
|
|
||||||
// Show help if no command provided
|
// Show help if no command provided
|
||||||
if (!process.argv.slice(2).length) {
|
if (process.argv.slice(2).length === 0) {
|
||||||
program.outputHelp();
|
program.outputHelp();
|
||||||
}
|
}
|
||||||
|
|
@ -30,12 +30,12 @@ ide-configurations:
|
||||||
# 2. Claude will switch to that agent's persona
|
# 2. Claude will switch to that agent's persona
|
||||||
windsurf:
|
windsurf:
|
||||||
name: Windsurf
|
name: Windsurf
|
||||||
rule-dir: .windsurf/rules/
|
rule-dir: .windsurf/workflows/
|
||||||
format: multi-file
|
format: multi-file
|
||||||
command-suffix: .md
|
command-suffix: .md
|
||||||
instructions: |
|
instructions: |
|
||||||
# To use BMad agents in Windsurf:
|
# To use BMad agents in Windsurf:
|
||||||
# 1. Type @agent-name (e.g., "@dev", "@pm")
|
# 1. Type /agent-name (e.g., "/dev", "/pm")
|
||||||
# 2. Windsurf will adopt that agent's persona
|
# 2. Windsurf will adopt that agent's persona
|
||||||
trae:
|
trae:
|
||||||
name: Trae
|
name: Trae
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const { extractYamlFromAgent } = require('../../lib/yaml-utils');
|
const { extractYamlFromAgent } = require('../../lib/yaml-utils');
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ class ConfigLoader {
|
||||||
id: agentId,
|
id: agentId,
|
||||||
name: agentConfig.title || agentConfig.name || agentId,
|
name: agentConfig.title || agentConfig.name || agentId,
|
||||||
file: `bmad-core/agents/${entry.name}`,
|
file: `bmad-core/agents/${entry.name}`,
|
||||||
description: agentConfig.whenToUse || 'No description available'
|
description: agentConfig.whenToUse || 'No description available',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -90,21 +90,25 @@ class ConfigLoader {
|
||||||
expansionPacks.push({
|
expansionPacks.push({
|
||||||
id: entry.name,
|
id: entry.name,
|
||||||
name: config.name || entry.name,
|
name: config.name || entry.name,
|
||||||
description: config['short-title'] || config.description || 'No description available',
|
description:
|
||||||
fullDescription: config.description || config['short-title'] || 'No description available',
|
config['short-title'] || config.description || 'No description available',
|
||||||
|
fullDescription:
|
||||||
|
config.description || config['short-title'] || 'No description available',
|
||||||
version: config.version || '1.0.0',
|
version: config.version || '1.0.0',
|
||||||
author: config.author || 'BMad Team',
|
author: config.author || 'BMad Team',
|
||||||
packPath: packPath,
|
packPath: packPath,
|
||||||
dependencies: config.dependencies?.agents || []
|
dependencies: config.dependencies?.agents || [],
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Fallback if config.yaml doesn't exist or can't be read
|
// Fallback if config.yaml doesn't exist or can't be read
|
||||||
console.warn(`Failed to read config for expansion pack ${entry.name}: ${error.message}`);
|
console.warn(
|
||||||
|
`Failed to read config for expansion pack ${entry.name}: ${error.message}`,
|
||||||
|
);
|
||||||
|
|
||||||
// Try to derive info from directory name as fallback
|
// Try to derive info from directory name as fallback
|
||||||
const name = entry.name
|
const name = entry.name
|
||||||
.split('-')
|
.split('-')
|
||||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||||
.join(' ');
|
.join(' ');
|
||||||
|
|
||||||
expansionPacks.push({
|
expansionPacks.push({
|
||||||
|
|
@ -115,7 +119,7 @@ class ConfigLoader {
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
author: 'BMad Team',
|
author: 'BMad Team',
|
||||||
packPath: packPath,
|
packPath: packPath,
|
||||||
dependencies: []
|
dependencies: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +197,7 @@ class ConfigLoader {
|
||||||
id: path.basename(entry.name, '.yaml'),
|
id: path.basename(entry.name, '.yaml'),
|
||||||
name: teamConfig.bundle.name || entry.name,
|
name: teamConfig.bundle.name || entry.name,
|
||||||
description: teamConfig.bundle.description || 'Team configuration',
|
description: teamConfig.bundle.description || 'Team configuration',
|
||||||
icon: teamConfig.bundle.icon || '📋'
|
icon: teamConfig.bundle.icon || '📋',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const path = require("path");
|
const path = require('node:path');
|
||||||
const crypto = require("crypto");
|
const crypto = require('node:crypto');
|
||||||
const yaml = require("js-yaml");
|
const yaml = require('js-yaml');
|
||||||
const chalk = require("chalk");
|
const chalk = require('chalk');
|
||||||
const { createReadStream, createWriteStream, promises: fsPromises } = require('fs');
|
const { createReadStream, createWriteStream, promises: fsPromises } = require('node:fs');
|
||||||
const { pipeline } = require('stream/promises');
|
const { pipeline } = require('node:stream/promises');
|
||||||
const resourceLocator = require('./resource-locator');
|
const resourceLocator = require('./resource-locator');
|
||||||
|
|
||||||
class FileManager {
|
class FileManager {
|
||||||
constructor() {
|
constructor() {}
|
||||||
this.manifestDir = ".bmad-core";
|
|
||||||
this.manifestFile = "install-manifest.yaml";
|
|
||||||
}
|
|
||||||
|
|
||||||
async copyFile(source, destination) {
|
async copyFile(source, destination) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -19,14 +16,9 @@ class FileManager {
|
||||||
|
|
||||||
// Use streaming for large files (> 10MB)
|
// Use streaming for large files (> 10MB)
|
||||||
const stats = await fs.stat(source);
|
const stats = await fs.stat(source);
|
||||||
if (stats.size > 10 * 1024 * 1024) {
|
await (stats.size > 10 * 1024 * 1024
|
||||||
await pipeline(
|
? pipeline(createReadStream(source), createWriteStream(destination))
|
||||||
createReadStream(source),
|
: fs.copy(source, destination));
|
||||||
createWriteStream(destination)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await fs.copy(source, destination);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red(`Failed to copy ${source}:`), error.message);
|
console.error(chalk.red(`Failed to copy ${source}:`), error.message);
|
||||||
|
|
@ -41,28 +33,20 @@ class FileManager {
|
||||||
// Use streaming copy for large directories
|
// Use streaming copy for large directories
|
||||||
const files = await resourceLocator.findFiles('**/*', {
|
const files = await resourceLocator.findFiles('**/*', {
|
||||||
cwd: source,
|
cwd: source,
|
||||||
nodir: true
|
nodir: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Process files in batches to avoid memory issues
|
// Process files in batches to avoid memory issues
|
||||||
const batchSize = 50;
|
const batchSize = 50;
|
||||||
for (let i = 0; i < files.length; i += batchSize) {
|
for (let index = 0; index < files.length; index += batchSize) {
|
||||||
const batch = files.slice(i, i + batchSize);
|
const batch = files.slice(index, index + batchSize);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
batch.map(file =>
|
batch.map((file) => this.copyFile(path.join(source, file), path.join(destination, file))),
|
||||||
this.copyFile(
|
|
||||||
path.join(source, file),
|
|
||||||
path.join(destination, file)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(chalk.red(`Failed to copy directory ${source}:`), error.message);
|
||||||
chalk.red(`Failed to copy directory ${source}:`),
|
|
||||||
error.message
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,17 +57,16 @@ class FileManager {
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const sourcePath = path.join(sourceDir, file);
|
const sourcePath = path.join(sourceDir, file);
|
||||||
const destPath = path.join(destDir, file);
|
const destinationPath = path.join(destDir, file);
|
||||||
|
|
||||||
// Use root replacement if rootValue is provided and file needs it
|
// Use root replacement if rootValue is provided and file needs it
|
||||||
const needsRootReplacement = rootValue && (file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml'));
|
const needsRootReplacement =
|
||||||
|
rootValue && (file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml'));
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
if (needsRootReplacement) {
|
success = await (needsRootReplacement
|
||||||
success = await this.copyFileWithRootReplacement(sourcePath, destPath, rootValue);
|
? this.copyFileWithRootReplacement(sourcePath, destinationPath, rootValue)
|
||||||
} else {
|
: this.copyFile(sourcePath, destinationPath));
|
||||||
success = await this.copyFile(sourcePath, destPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
copied.push(file);
|
copied.push(file);
|
||||||
|
|
@ -97,32 +80,28 @@ class FileManager {
|
||||||
try {
|
try {
|
||||||
// Use streaming for hash calculation to reduce memory usage
|
// Use streaming for hash calculation to reduce memory usage
|
||||||
const stream = createReadStream(filePath);
|
const stream = createReadStream(filePath);
|
||||||
const hash = crypto.createHash("sha256");
|
const hash = crypto.createHash('sha256');
|
||||||
|
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
hash.update(chunk);
|
hash.update(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash.digest("hex").slice(0, 16);
|
return hash.digest('hex').slice(0, 16);
|
||||||
} catch (error) {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createManifest(installDir, config, files) {
|
async createManifest(installDir, config, files) {
|
||||||
const manifestPath = path.join(
|
const manifestPath = path.join(installDir, this.manifestDir, this.manifestFile);
|
||||||
installDir,
|
|
||||||
this.manifestDir,
|
|
||||||
this.manifestFile
|
|
||||||
);
|
|
||||||
|
|
||||||
// Read version from package.json
|
// Read version from package.json
|
||||||
let coreVersion = "unknown";
|
let coreVersion = 'unknown';
|
||||||
try {
|
try {
|
||||||
const packagePath = path.join(__dirname, '..', '..', '..', 'package.json');
|
const packagePath = path.join(__dirname, '..', '..', '..', 'package.json');
|
||||||
const packageJson = require(packagePath);
|
const packageJson = require(packagePath);
|
||||||
coreVersion = packageJson.version;
|
coreVersion = packageJson.version;
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.warn("Could not read version from package.json, using 'unknown'");
|
console.warn("Could not read version from package.json, using 'unknown'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,31 +135,23 @@ class FileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async readManifest(installDir) {
|
async readManifest(installDir) {
|
||||||
const manifestPath = path.join(
|
const manifestPath = path.join(installDir, this.manifestDir, this.manifestFile);
|
||||||
installDir,
|
|
||||||
this.manifestDir,
|
|
||||||
this.manifestFile
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(manifestPath, "utf8");
|
const content = await fs.readFile(manifestPath, 'utf8');
|
||||||
return yaml.load(content);
|
return yaml.load(content);
|
||||||
} catch (error) {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async readExpansionPackManifest(installDir, packId) {
|
async readExpansionPackManifest(installDir, packId) {
|
||||||
const manifestPath = path.join(
|
const manifestPath = path.join(installDir, `.${packId}`, this.manifestFile);
|
||||||
installDir,
|
|
||||||
`.${packId}`,
|
|
||||||
this.manifestFile
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(manifestPath, "utf8");
|
const content = await fs.readFile(manifestPath, 'utf8');
|
||||||
return yaml.load(content);
|
return yaml.load(content);
|
||||||
} catch (error) {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +174,7 @@ class FileManager {
|
||||||
async checkFileIntegrity(installDir, manifest) {
|
async checkFileIntegrity(installDir, manifest) {
|
||||||
const result = {
|
const result = {
|
||||||
missing: [],
|
missing: [],
|
||||||
modified: []
|
modified: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const file of manifest.files) {
|
for (const file of manifest.files) {
|
||||||
|
|
@ -214,13 +185,13 @@ class FileManager {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await this.pathExists(filePath))) {
|
if (await this.pathExists(filePath)) {
|
||||||
result.missing.push(file.path);
|
|
||||||
} else {
|
|
||||||
const currentHash = await this.calculateFileHash(filePath);
|
const currentHash = await this.calculateFileHash(filePath);
|
||||||
if (currentHash && currentHash !== file.hash) {
|
if (currentHash && currentHash !== file.hash) {
|
||||||
result.modified.push(file.path);
|
result.modified.push(file.path);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
result.missing.push(file.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,7 +199,7 @@ class FileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async backupFile(filePath) {
|
async backupFile(filePath) {
|
||||||
const backupPath = filePath + ".bak";
|
const backupPath = filePath + '.bak';
|
||||||
let counter = 1;
|
let counter = 1;
|
||||||
let finalBackupPath = backupPath;
|
let finalBackupPath = backupPath;
|
||||||
|
|
||||||
|
|
@ -256,7 +227,7 @@ class FileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async readFile(filePath) {
|
async readFile(filePath) {
|
||||||
return fs.readFile(filePath, "utf8");
|
return fs.readFile(filePath, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
async writeFile(filePath, content) {
|
async writeFile(filePath, content) {
|
||||||
|
|
@ -269,14 +240,10 @@ class FileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async createExpansionPackManifest(installDir, packId, config, files) {
|
async createExpansionPackManifest(installDir, packId, config, files) {
|
||||||
const manifestPath = path.join(
|
const manifestPath = path.join(installDir, `.${packId}`, this.manifestFile);
|
||||||
installDir,
|
|
||||||
`.${packId}`,
|
|
||||||
this.manifestFile
|
|
||||||
);
|
|
||||||
|
|
||||||
const manifest = {
|
const manifest = {
|
||||||
version: config.expansionPackVersion || require("../../../package.json").version,
|
version: config.expansionPackVersion || require('../../../package.json').version,
|
||||||
installed_at: new Date().toISOString(),
|
installed_at: new Date().toISOString(),
|
||||||
install_type: config.installType,
|
install_type: config.installType,
|
||||||
expansion_pack_id: config.expansionPackId,
|
expansion_pack_id: config.expansionPackId,
|
||||||
|
|
@ -336,26 +303,27 @@ class FileManager {
|
||||||
// Check file size to determine if we should stream
|
// Check file size to determine if we should stream
|
||||||
const stats = await fs.stat(source);
|
const stats = await fs.stat(source);
|
||||||
|
|
||||||
if (stats.size > 5 * 1024 * 1024) { // 5MB threshold
|
if (stats.size > 5 * 1024 * 1024) {
|
||||||
|
// 5MB threshold
|
||||||
// Use streaming for large files
|
// Use streaming for large files
|
||||||
const { Transform } = require('stream');
|
const { Transform } = require('node:stream');
|
||||||
const replaceStream = new Transform({
|
const replaceStream = new Transform({
|
||||||
transform(chunk, encoding, callback) {
|
transform(chunk, encoding, callback) {
|
||||||
const modified = chunk.toString().replace(/\{root\}/g, rootValue);
|
const modified = chunk.toString().replaceAll('{root}', rootValue);
|
||||||
callback(null, modified);
|
callback(null, modified);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.ensureDirectory(path.dirname(destination));
|
await this.ensureDirectory(path.dirname(destination));
|
||||||
await pipeline(
|
await pipeline(
|
||||||
createReadStream(source, { encoding: 'utf8' }),
|
createReadStream(source, { encoding: 'utf8' }),
|
||||||
replaceStream,
|
replaceStream,
|
||||||
createWriteStream(destination, { encoding: 'utf8' })
|
createWriteStream(destination, { encoding: 'utf8' }),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Regular approach for smaller files
|
// Regular approach for smaller files
|
||||||
const content = await fsPromises.readFile(source, 'utf8');
|
const content = await fsPromises.readFile(source, 'utf8');
|
||||||
const updatedContent = content.replace(/\{root\}/g, rootValue);
|
const updatedContent = content.replaceAll('{root}', rootValue);
|
||||||
await this.ensureDirectory(path.dirname(destination));
|
await this.ensureDirectory(path.dirname(destination));
|
||||||
await fsPromises.writeFile(destination, updatedContent, 'utf8');
|
await fsPromises.writeFile(destination, updatedContent, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
@ -367,32 +335,37 @@ class FileManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async copyDirectoryWithRootReplacement(source, destination, rootValue, fileExtensions = ['.md', '.yaml', '.yml']) {
|
async copyDirectoryWithRootReplacement(
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
rootValue,
|
||||||
|
fileExtensions = ['.md', '.yaml', '.yml'],
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
await this.ensureDirectory(destination);
|
await this.ensureDirectory(destination);
|
||||||
|
|
||||||
// Get all files in source directory
|
// Get all files in source directory
|
||||||
const files = await resourceLocator.findFiles('**/*', {
|
const files = await resourceLocator.findFiles('**/*', {
|
||||||
cwd: source,
|
cwd: source,
|
||||||
nodir: true
|
nodir: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
let replacedCount = 0;
|
let replacedCount = 0;
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const sourcePath = path.join(source, file);
|
const sourcePath = path.join(source, file);
|
||||||
const destPath = path.join(destination, file);
|
const destinationPath = path.join(destination, file);
|
||||||
|
|
||||||
// Check if this file type should have {root} replacement
|
// Check if this file type should have {root} replacement
|
||||||
const shouldReplace = fileExtensions.some(ext => file.endsWith(ext));
|
const shouldReplace = fileExtensions.some((extension) => file.endsWith(extension));
|
||||||
|
|
||||||
if (shouldReplace) {
|
if (shouldReplace) {
|
||||||
if (await this.copyFileWithRootReplacement(sourcePath, destPath, rootValue)) {
|
if (await this.copyFileWithRootReplacement(sourcePath, destinationPath, rootValue)) {
|
||||||
replacedCount++;
|
replacedCount++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular copy for files that don't need replacement
|
// Regular copy for files that don't need replacement
|
||||||
await this.copyFile(sourcePath, destPath);
|
await this.copyFile(sourcePath, destinationPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,10 +375,15 @@ class FileManager {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red(`Failed to copy directory ${source} with root replacement:`), error.message);
|
console.error(
|
||||||
|
chalk.red(`Failed to copy directory ${source} with root replacement:`),
|
||||||
|
error.message,
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
manifestDir = '.bmad-core';
|
||||||
|
manifestFile = 'install-manifest.yaml';
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new FileManager();
|
module.exports = new FileManager();
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@
|
||||||
* Reduces duplication and provides shared methods
|
* Reduces duplication and provides shared methods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const path = require("path");
|
const path = require('node:path');
|
||||||
const fs = require("fs-extra");
|
const fs = require('fs-extra');
|
||||||
const yaml = require("js-yaml");
|
const yaml = require('js-yaml');
|
||||||
const chalk = require("chalk");
|
const chalk = require('chalk');
|
||||||
const fileManager = require("./file-manager");
|
const fileManager = require('./file-manager');
|
||||||
const resourceLocator = require("./resource-locator");
|
const resourceLocator = require('./resource-locator');
|
||||||
const { extractYamlFromAgent } = require("../../lib/yaml-utils");
|
const { extractYamlFromAgent } = require('../../lib/yaml-utils');
|
||||||
|
|
||||||
class BaseIdeSetup {
|
class BaseIdeSetup {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -30,16 +30,16 @@ class BaseIdeSetup {
|
||||||
|
|
||||||
// Get core agents
|
// Get core agents
|
||||||
const coreAgents = await this.getCoreAgentIds(installDir);
|
const coreAgents = await this.getCoreAgentIds(installDir);
|
||||||
coreAgents.forEach(id => allAgents.add(id));
|
for (const id of coreAgents) allAgents.add(id);
|
||||||
|
|
||||||
// Get expansion pack agents
|
// Get expansion pack agents
|
||||||
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
||||||
for (const pack of expansionPacks) {
|
for (const pack of expansionPacks) {
|
||||||
const packAgents = await this.getExpansionPackAgents(pack.path);
|
const packAgents = await this.getExpansionPackAgents(pack.path);
|
||||||
packAgents.forEach(id => allAgents.add(id));
|
for (const id of packAgents) allAgents.add(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = Array.from(allAgents);
|
const result = [...allAgents];
|
||||||
this._agentCache.set(cacheKey, result);
|
this._agentCache.set(cacheKey, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -50,14 +50,14 @@ class BaseIdeSetup {
|
||||||
async getCoreAgentIds(installDir) {
|
async getCoreAgentIds(installDir) {
|
||||||
const coreAgents = [];
|
const coreAgents = [];
|
||||||
const corePaths = [
|
const corePaths = [
|
||||||
path.join(installDir, ".bmad-core", "agents"),
|
path.join(installDir, '.bmad-core', 'agents'),
|
||||||
path.join(installDir, "bmad-core", "agents")
|
path.join(installDir, 'bmad-core', 'agents'),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const agentsDir of corePaths) {
|
for (const agentsDir of corePaths) {
|
||||||
if (await fileManager.pathExists(agentsDir)) {
|
if (await fileManager.pathExists(agentsDir)) {
|
||||||
const files = await resourceLocator.findFiles("*.md", { cwd: agentsDir });
|
const files = await resourceLocator.findFiles('*.md', { cwd: agentsDir });
|
||||||
coreAgents.push(...files.map(file => path.basename(file, ".md")));
|
coreAgents.push(...files.map((file) => path.basename(file, '.md')));
|
||||||
break; // Use first found
|
break; // Use first found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,9 +80,9 @@ class BaseIdeSetup {
|
||||||
if (!agentPath) {
|
if (!agentPath) {
|
||||||
// Check installation-specific paths
|
// Check installation-specific paths
|
||||||
const possiblePaths = [
|
const possiblePaths = [
|
||||||
path.join(installDir, ".bmad-core", "agents", `${agentId}.md`),
|
path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
|
||||||
path.join(installDir, "bmad-core", "agents", `${agentId}.md`),
|
path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`),
|
||||||
path.join(installDir, "common", "agents", `${agentId}.md`)
|
path.join(installDir, 'common', 'agents', `${agentId}.md`),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const testPath of possiblePaths) {
|
for (const testPath of possiblePaths) {
|
||||||
|
|
@ -113,7 +113,7 @@ class BaseIdeSetup {
|
||||||
const metadata = yaml.load(yamlContent);
|
const metadata = yaml.load(yamlContent);
|
||||||
return metadata.agent_name || agentId;
|
return metadata.agent_name || agentId;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Fallback to agent ID
|
// Fallback to agent ID
|
||||||
}
|
}
|
||||||
return agentId;
|
return agentId;
|
||||||
|
|
@ -131,29 +131,29 @@ class BaseIdeSetup {
|
||||||
const expansionPacks = [];
|
const expansionPacks = [];
|
||||||
|
|
||||||
// Check for dot-prefixed expansion packs
|
// Check for dot-prefixed expansion packs
|
||||||
const dotExpansions = await resourceLocator.findFiles(".bmad-*", { cwd: installDir });
|
const dotExpansions = await resourceLocator.findFiles('.bmad-*', { cwd: installDir });
|
||||||
|
|
||||||
for (const dotExpansion of dotExpansions) {
|
for (const dotExpansion of dotExpansions) {
|
||||||
if (dotExpansion !== ".bmad-core") {
|
if (dotExpansion !== '.bmad-core') {
|
||||||
const packPath = path.join(installDir, dotExpansion);
|
const packPath = path.join(installDir, dotExpansion);
|
||||||
const packName = dotExpansion.substring(1); // remove the dot
|
const packName = dotExpansion.slice(1); // remove the dot
|
||||||
expansionPacks.push({
|
expansionPacks.push({
|
||||||
name: packName,
|
name: packName,
|
||||||
path: packPath
|
path: packPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check other dot folders that have config.yaml
|
// Check other dot folders that have config.yaml
|
||||||
const allDotFolders = await resourceLocator.findFiles(".*", { cwd: installDir });
|
const allDotFolders = await resourceLocator.findFiles('.*', { cwd: installDir });
|
||||||
for (const folder of allDotFolders) {
|
for (const folder of allDotFolders) {
|
||||||
if (!folder.startsWith(".bmad-") && folder !== ".bmad-core") {
|
if (!folder.startsWith('.bmad-') && folder !== '.bmad-core') {
|
||||||
const packPath = path.join(installDir, folder);
|
const packPath = path.join(installDir, folder);
|
||||||
const configPath = path.join(packPath, "config.yaml");
|
const configPath = path.join(packPath, 'config.yaml');
|
||||||
if (await fileManager.pathExists(configPath)) {
|
if (await fileManager.pathExists(configPath)) {
|
||||||
expansionPacks.push({
|
expansionPacks.push({
|
||||||
name: folder.substring(1), // remove the dot
|
name: folder.slice(1), // remove the dot
|
||||||
path: packPath
|
path: packPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,13 +167,13 @@ class BaseIdeSetup {
|
||||||
* Get expansion pack agents
|
* Get expansion pack agents
|
||||||
*/
|
*/
|
||||||
async getExpansionPackAgents(packPath) {
|
async getExpansionPackAgents(packPath) {
|
||||||
const agentsDir = path.join(packPath, "agents");
|
const agentsDir = path.join(packPath, 'agents');
|
||||||
if (!(await fileManager.pathExists(agentsDir))) {
|
if (!(await fileManager.pathExists(agentsDir))) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const agentFiles = await resourceLocator.findFiles("*.md", { cwd: agentsDir });
|
const agentFiles = await resourceLocator.findFiles('*.md', { cwd: agentsDir });
|
||||||
return agentFiles.map(file => path.basename(file, ".md"));
|
return agentFiles.map((file) => path.basename(file, '.md'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -184,26 +184,27 @@ class BaseIdeSetup {
|
||||||
const agentTitle = await this.getAgentTitle(agentId, installDir);
|
const agentTitle = await this.getAgentTitle(agentId, installDir);
|
||||||
const yamlContent = extractYamlFromAgent(agentContent);
|
const yamlContent = extractYamlFromAgent(agentContent);
|
||||||
|
|
||||||
let content = "";
|
let content = '';
|
||||||
|
|
||||||
if (format === 'mdc') {
|
if (format === 'mdc') {
|
||||||
// MDC format for Cursor
|
// MDC format for Cursor
|
||||||
content = "---\n";
|
content = '---\n';
|
||||||
content += "description: \n";
|
content += 'description: \n';
|
||||||
content += "globs: []\n";
|
content += 'globs: []\n';
|
||||||
content += "alwaysApply: false\n";
|
content += 'alwaysApply: false\n';
|
||||||
content += "---\n\n";
|
content += '---\n\n';
|
||||||
content += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
content += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
||||||
content += `This rule is triggered when the user types \`@${agentId}\` and activates the ${agentTitle} agent persona.\n\n`;
|
content += `This rule is triggered when the user types \`@${agentId}\` and activates the ${agentTitle} agent persona.\n\n`;
|
||||||
content += "## Agent Activation\n\n";
|
content += '## Agent Activation\n\n';
|
||||||
content += "CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
|
content +=
|
||||||
content += "```yaml\n";
|
'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
|
||||||
content += yamlContent || agentContent.replace(/^#.*$/m, "").trim();
|
content += '```yaml\n';
|
||||||
content += "\n```\n\n";
|
content += yamlContent || agentContent.replace(/^#.*$/m, '').trim();
|
||||||
content += "## File Reference\n\n";
|
content += '\n```\n\n';
|
||||||
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
content += '## File Reference\n\n';
|
||||||
|
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
||||||
content += `The complete agent definition is available in [${relativePath}](mdc:${relativePath}).\n\n`;
|
content += `The complete agent definition is available in [${relativePath}](mdc:${relativePath}).\n\n`;
|
||||||
content += "## Usage\n\n";
|
content += '## Usage\n\n';
|
||||||
content += `When the user types \`@${agentId}\`, activate this ${agentTitle} persona and follow all instructions defined in the YAML configuration above.\n`;
|
content += `When the user types \`@${agentId}\`, activate this ${agentTitle} persona and follow all instructions defined in the YAML configuration above.\n`;
|
||||||
} else if (format === 'claude') {
|
} else if (format === 'claude') {
|
||||||
// Claude Code format
|
// Claude Code format
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -3,7 +3,7 @@
|
||||||
* Helps identify memory leaks and optimize resource usage
|
* Helps identify memory leaks and optimize resource usage
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const v8 = require('v8');
|
const v8 = require('node:v8');
|
||||||
|
|
||||||
class MemoryProfiler {
|
class MemoryProfiler {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -28,18 +28,18 @@ class MemoryProfiler {
|
||||||
heapTotal: this.formatBytes(memUsage.heapTotal),
|
heapTotal: this.formatBytes(memUsage.heapTotal),
|
||||||
heapUsed: this.formatBytes(memUsage.heapUsed),
|
heapUsed: this.formatBytes(memUsage.heapUsed),
|
||||||
external: this.formatBytes(memUsage.external),
|
external: this.formatBytes(memUsage.external),
|
||||||
arrayBuffers: this.formatBytes(memUsage.arrayBuffers || 0)
|
arrayBuffers: this.formatBytes(memUsage.arrayBuffers || 0),
|
||||||
},
|
},
|
||||||
heap: {
|
heap: {
|
||||||
totalHeapSize: this.formatBytes(heapStats.total_heap_size),
|
totalHeapSize: this.formatBytes(heapStats.total_heap_size),
|
||||||
usedHeapSize: this.formatBytes(heapStats.used_heap_size),
|
usedHeapSize: this.formatBytes(heapStats.used_heap_size),
|
||||||
heapSizeLimit: this.formatBytes(heapStats.heap_size_limit),
|
heapSizeLimit: this.formatBytes(heapStats.heap_size_limit),
|
||||||
mallocedMemory: this.formatBytes(heapStats.malloced_memory),
|
mallocedMemory: this.formatBytes(heapStats.malloced_memory),
|
||||||
externalMemory: this.formatBytes(heapStats.external_memory)
|
externalMemory: this.formatBytes(heapStats.external_memory),
|
||||||
},
|
},
|
||||||
raw: {
|
raw: {
|
||||||
heapUsed: memUsage.heapUsed
|
heapUsed: memUsage.heapUsed,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Track peak memory
|
// Track peak memory
|
||||||
|
|
@ -55,8 +55,8 @@ class MemoryProfiler {
|
||||||
* Force garbage collection (requires --expose-gc flag)
|
* Force garbage collection (requires --expose-gc flag)
|
||||||
*/
|
*/
|
||||||
forceGC() {
|
forceGC() {
|
||||||
if (global.gc) {
|
if (globalThis.gc) {
|
||||||
global.gc();
|
globalThis.gc();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -72,11 +72,11 @@ class MemoryProfiler {
|
||||||
currentUsage: {
|
currentUsage: {
|
||||||
rss: this.formatBytes(currentMemory.rss),
|
rss: this.formatBytes(currentMemory.rss),
|
||||||
heapTotal: this.formatBytes(currentMemory.heapTotal),
|
heapTotal: this.formatBytes(currentMemory.heapTotal),
|
||||||
heapUsed: this.formatBytes(currentMemory.heapUsed)
|
heapUsed: this.formatBytes(currentMemory.heapUsed),
|
||||||
},
|
},
|
||||||
peakMemory: this.formatBytes(this.peakMemory),
|
peakMemory: this.formatBytes(this.peakMemory),
|
||||||
totalCheckpoints: this.checkpoints.length,
|
totalCheckpoints: this.checkpoints.length,
|
||||||
runTime: `${((Date.now() - this.startTime) / 1000).toFixed(2)}s`
|
runTime: `${((Date.now() - this.startTime) / 1000).toFixed(2)}s`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ class MemoryProfiler {
|
||||||
summary,
|
summary,
|
||||||
memoryGrowth,
|
memoryGrowth,
|
||||||
checkpoints: this.checkpoints,
|
checkpoints: this.checkpoints,
|
||||||
recommendations: this.getRecommendations(memoryGrowth)
|
recommendations: this.getRecommendations(memoryGrowth),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,18 +102,18 @@ class MemoryProfiler {
|
||||||
if (this.checkpoints.length < 2) return [];
|
if (this.checkpoints.length < 2) return [];
|
||||||
|
|
||||||
const growth = [];
|
const growth = [];
|
||||||
for (let i = 1; i < this.checkpoints.length; i++) {
|
for (let index = 1; index < this.checkpoints.length; index++) {
|
||||||
const prev = this.checkpoints[i - 1];
|
const previous = this.checkpoints[index - 1];
|
||||||
const curr = this.checkpoints[i];
|
const current = this.checkpoints[index];
|
||||||
|
|
||||||
const heapDiff = curr.raw.heapUsed - prev.raw.heapUsed;
|
const heapDiff = current.raw.heapUsed - previous.raw.heapUsed;
|
||||||
|
|
||||||
growth.push({
|
growth.push({
|
||||||
from: prev.label,
|
from: previous.label,
|
||||||
to: curr.label,
|
to: current.label,
|
||||||
heapGrowth: this.formatBytes(Math.abs(heapDiff)),
|
heapGrowth: this.formatBytes(Math.abs(heapDiff)),
|
||||||
isIncrease: heapDiff > 0,
|
isIncrease: heapDiff > 0,
|
||||||
timeDiff: `${((curr.timestamp - prev.timestamp) / 1000).toFixed(2)}s`
|
timeDiff: `${((current.timestamp - previous.timestamp) / 1000).toFixed(2)}s`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +127,7 @@ class MemoryProfiler {
|
||||||
const recommendations = [];
|
const recommendations = [];
|
||||||
|
|
||||||
// Check for large memory growth
|
// Check for large memory growth
|
||||||
const largeGrowths = memoryGrowth.filter(g => {
|
const largeGrowths = memoryGrowth.filter((g) => {
|
||||||
const bytes = this.parseBytes(g.heapGrowth);
|
const bytes = this.parseBytes(g.heapGrowth);
|
||||||
return bytes > 50 * 1024 * 1024; // 50MB
|
return bytes > 50 * 1024 * 1024; // 50MB
|
||||||
});
|
});
|
||||||
|
|
@ -136,16 +136,17 @@ class MemoryProfiler {
|
||||||
recommendations.push({
|
recommendations.push({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
message: `Large memory growth detected in ${largeGrowths.length} operations`,
|
message: `Large memory growth detected in ${largeGrowths.length} operations`,
|
||||||
details: largeGrowths.map(g => `${g.from} → ${g.to}: ${g.heapGrowth}`)
|
details: largeGrowths.map((g) => `${g.from} → ${g.to}: ${g.heapGrowth}`),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check peak memory
|
// Check peak memory
|
||||||
if (this.peakMemory > 500 * 1024 * 1024) { // 500MB
|
if (this.peakMemory > 500 * 1024 * 1024) {
|
||||||
|
// 500MB
|
||||||
recommendations.push({
|
recommendations.push({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
message: `High peak memory usage: ${this.formatBytes(this.peakMemory)}`,
|
message: `High peak memory usage: ${this.formatBytes(this.peakMemory)}`,
|
||||||
suggestion: 'Consider processing files in smaller batches'
|
suggestion: 'Consider processing files in smaller batches',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +156,7 @@ class MemoryProfiler {
|
||||||
recommendations.push({
|
recommendations.push({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: 'Potential memory leak detected',
|
message: 'Potential memory leak detected',
|
||||||
details: 'Memory usage continuously increases without significant decreases'
|
details: 'Memory usage continuously increases without significant decreases',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,8 +170,8 @@ class MemoryProfiler {
|
||||||
if (this.checkpoints.length < 5) return false;
|
if (this.checkpoints.length < 5) return false;
|
||||||
|
|
||||||
let increasingCount = 0;
|
let increasingCount = 0;
|
||||||
for (let i = 1; i < this.checkpoints.length; i++) {
|
for (let index = 1; index < this.checkpoints.length; index++) {
|
||||||
if (this.checkpoints[i].raw.heapUsed > this.checkpoints[i - 1].raw.heapUsed) {
|
if (this.checkpoints[index].raw.heapUsed > this.checkpoints[index - 1].raw.heapUsed) {
|
||||||
increasingCount++;
|
increasingCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -187,26 +188,26 @@ class MemoryProfiler {
|
||||||
|
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const index = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
return Number.parseFloat((bytes / Math.pow(k, index)).toFixed(2)) + ' ' + sizes[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse human-readable bytes back to number
|
* Parse human-readable bytes back to number
|
||||||
*/
|
*/
|
||||||
parseBytes(str) {
|
parseBytes(string_) {
|
||||||
const match = str.match(/^([\d.]+)\s*([KMGT]?B?)$/i);
|
const match = string_.match(/^([\d.]+)\s*([KMGT]?B?)$/i);
|
||||||
if (!match) return 0;
|
if (!match) return 0;
|
||||||
|
|
||||||
const value = parseFloat(match[1]);
|
const value = Number.parseFloat(match[1]);
|
||||||
const unit = match[2].toUpperCase();
|
const unit = match[2].toUpperCase();
|
||||||
|
|
||||||
const multipliers = {
|
const multipliers = {
|
||||||
'B': 1,
|
B: 1,
|
||||||
'KB': 1024,
|
KB: 1024,
|
||||||
'MB': 1024 * 1024,
|
MB: 1024 * 1024,
|
||||||
'GB': 1024 * 1024 * 1024
|
GB: 1024 * 1024 * 1024,
|
||||||
};
|
};
|
||||||
|
|
||||||
return value * (multipliers[unit] || 1);
|
return value * (multipliers[unit] || 1);
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@ class ModuleManager {
|
||||||
const modules = await Promise.all([
|
const modules = await Promise.all([
|
||||||
this.getModule('chalk'),
|
this.getModule('chalk'),
|
||||||
this.getModule('ora'),
|
this.getModule('ora'),
|
||||||
this.getModule('inquirer')
|
this.getModule('inquirer'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chalk: modules[0],
|
chalk: modules[0],
|
||||||
ora: modules[1],
|
ora: modules[1],
|
||||||
inquirer: modules[2]
|
inquirer: modules[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,20 +64,26 @@ class ModuleManager {
|
||||||
*/
|
*/
|
||||||
async _loadModule(moduleName) {
|
async _loadModule(moduleName) {
|
||||||
switch (moduleName) {
|
switch (moduleName) {
|
||||||
case 'chalk':
|
case 'chalk': {
|
||||||
return (await import('chalk')).default;
|
return (await import('chalk')).default;
|
||||||
case 'ora':
|
}
|
||||||
|
case 'ora': {
|
||||||
return (await import('ora')).default;
|
return (await import('ora')).default;
|
||||||
case 'inquirer':
|
}
|
||||||
|
case 'inquirer': {
|
||||||
return (await import('inquirer')).default;
|
return (await import('inquirer')).default;
|
||||||
case 'glob':
|
}
|
||||||
|
case 'glob': {
|
||||||
return (await import('glob')).glob;
|
return (await import('glob')).glob;
|
||||||
case 'globSync':
|
}
|
||||||
|
case 'globSync': {
|
||||||
return (await import('glob')).globSync;
|
return (await import('glob')).globSync;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
throw new Error(`Unknown module: ${moduleName}`);
|
throw new Error(`Unknown module: ${moduleName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the module cache to free memory
|
* Clear the module cache to free memory
|
||||||
|
|
@ -93,13 +99,11 @@ class ModuleManager {
|
||||||
* @returns {Promise<Object>} Object with module names as keys
|
* @returns {Promise<Object>} Object with module names as keys
|
||||||
*/
|
*/
|
||||||
async getModules(moduleNames) {
|
async getModules(moduleNames) {
|
||||||
const modules = await Promise.all(
|
const modules = await Promise.all(moduleNames.map((name) => this.getModule(name)));
|
||||||
moduleNames.map(name => this.getModule(name))
|
|
||||||
);
|
|
||||||
|
|
||||||
return moduleNames.reduce((acc, name, index) => {
|
return moduleNames.reduce((accumulator, name, index) => {
|
||||||
acc[name] = modules[index];
|
accumulator[name] = modules[index];
|
||||||
return acc;
|
return accumulator;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,14 +107,11 @@ class ResourceLocator {
|
||||||
|
|
||||||
// Get agents from bmad-core
|
// Get agents from bmad-core
|
||||||
const coreAgents = await this.findFiles('agents/*.md', {
|
const coreAgents = await this.findFiles('agents/*.md', {
|
||||||
cwd: this.getBmadCorePath()
|
cwd: this.getBmadCorePath(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const agentFile of coreAgents) {
|
for (const agentFile of coreAgents) {
|
||||||
const content = await fs.readFile(
|
const content = await fs.readFile(path.join(this.getBmadCorePath(), agentFile), 'utf8');
|
||||||
path.join(this.getBmadCorePath(), agentFile),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
const yamlContent = extractYamlFromAgent(content);
|
const yamlContent = extractYamlFromAgent(content);
|
||||||
if (yamlContent) {
|
if (yamlContent) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -123,9 +120,9 @@ class ResourceLocator {
|
||||||
id: path.basename(agentFile, '.md'),
|
id: path.basename(agentFile, '.md'),
|
||||||
name: metadata.agent_name || path.basename(agentFile, '.md'),
|
name: metadata.agent_name || path.basename(agentFile, '.md'),
|
||||||
description: metadata.description || 'No description available',
|
description: metadata.description || 'No description available',
|
||||||
source: 'core'
|
source: 'core',
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Skip invalid agents
|
// Skip invalid agents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,11 +164,12 @@ class ResourceLocator {
|
||||||
name: config.name || entry.name,
|
name: config.name || entry.name,
|
||||||
version: config.version || '1.0.0',
|
version: config.version || '1.0.0',
|
||||||
description: config.description || 'No description available',
|
description: config.description || 'No description available',
|
||||||
shortTitle: config['short-title'] || config.description || 'No description available',
|
shortTitle:
|
||||||
|
config['short-title'] || config.description || 'No description available',
|
||||||
author: config.author || 'Unknown',
|
author: config.author || 'Unknown',
|
||||||
path: path.join(expansionPacksPath, entry.name)
|
path: path.join(expansionPacksPath, entry.name),
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Skip invalid packs
|
// Skip invalid packs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +205,7 @@ class ResourceLocator {
|
||||||
const config = yaml.load(content);
|
const config = yaml.load(content);
|
||||||
this._pathCache.set(cacheKey, config);
|
this._pathCache.set(cacheKey, config);
|
||||||
return config;
|
return config;
|
||||||
} catch (e) {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -261,7 +259,7 @@ class ResourceLocator {
|
||||||
const result = { all: allDeps, byType };
|
const result = { all: allDeps, byType };
|
||||||
this._pathCache.set(cacheKey, result);
|
this._pathCache.set(cacheKey, result);
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch {
|
||||||
return { all: [], byType: {} };
|
return { all: [], byType: {} };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +293,7 @@ class ResourceLocator {
|
||||||
const config = yaml.load(content);
|
const config = yaml.load(content);
|
||||||
this._pathCache.set(cacheKey, config);
|
this._pathCache.set(cacheKey, config);
|
||||||
return config;
|
return config;
|
||||||
} catch (e) {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,6 @@
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "4.36.2",
|
"version": "4.36.2",
|
||||||
"description": "BMad Method installer - AI-powered Agile development framework",
|
"description": "BMad Method installer - AI-powered Agile development framework",
|
||||||
"main": "lib/installer.js",
|
|
||||||
"bin": {
|
|
||||||
"bmad": "./bin/bmad.js",
|
|
||||||
"bmad-method": "./bin/bmad.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bmad",
|
"bmad",
|
||||||
"agile",
|
"agile",
|
||||||
|
|
@ -19,8 +11,24 @@
|
||||||
"installer",
|
"installer",
|
||||||
"agents"
|
"agents"
|
||||||
],
|
],
|
||||||
"author": "BMad Team",
|
"homepage": "https://github.com/bmad-team/bmad-method#readme",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/bmad-team/bmad-method/issues"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/bmad-team/bmad-method.git"
|
||||||
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"author": "BMad Team",
|
||||||
|
"main": "lib/installer.js",
|
||||||
|
"bin": {
|
||||||
|
"bmad": "./bin/bmad.js",
|
||||||
|
"bmad-method": "./bin/bmad.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"commander": "^14.0.0",
|
"commander": "^14.0.0",
|
||||||
|
|
@ -31,13 +39,5 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
},
|
}
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/bmad-team/bmad-method.git"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/bmad-team/bmad-method/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/bmad-team/bmad-method#readme"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
const fs = require('fs').promises;
|
const fs = require('node:fs').promises;
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const { extractYamlFromAgent } = require('./yaml-utils');
|
const { extractYamlFromAgent } = require('./yaml-utils');
|
||||||
|
|
||||||
|
|
@ -28,9 +28,9 @@ class DependencyResolver {
|
||||||
id: agentId,
|
id: agentId,
|
||||||
path: agentPath,
|
path: agentPath,
|
||||||
content: agentContent,
|
content: agentContent,
|
||||||
config: agentConfig
|
config: agentConfig,
|
||||||
},
|
},
|
||||||
resources: []
|
resources: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Personas are now embedded in agent configs, no need to resolve separately
|
// Personas are now embedded in agent configs, no need to resolve separately
|
||||||
|
|
@ -58,18 +58,18 @@ class DependencyResolver {
|
||||||
id: teamId,
|
id: teamId,
|
||||||
path: teamPath,
|
path: teamPath,
|
||||||
content: teamContent,
|
content: teamContent,
|
||||||
config: teamConfig
|
config: teamConfig,
|
||||||
},
|
},
|
||||||
agents: [],
|
agents: [],
|
||||||
resources: new Map() // Use Map to deduplicate resources
|
resources: new Map(), // Use Map to deduplicate resources
|
||||||
};
|
};
|
||||||
|
|
||||||
// Always add bmad-orchestrator agent first if it's a team
|
// Always add bmad-orchestrator agent first if it's a team
|
||||||
const bmadAgent = await this.resolveAgentDependencies('bmad-orchestrator');
|
const bmadAgent = await this.resolveAgentDependencies('bmad-orchestrator');
|
||||||
dependencies.agents.push(bmadAgent.agent);
|
dependencies.agents.push(bmadAgent.agent);
|
||||||
bmadAgent.resources.forEach(res => {
|
for (const res of bmadAgent.resources) {
|
||||||
dependencies.resources.set(res.path, res);
|
dependencies.resources.set(res.path, res);
|
||||||
});
|
}
|
||||||
|
|
||||||
// Resolve all agents in the team
|
// Resolve all agents in the team
|
||||||
let agentsToResolve = teamConfig.agents || [];
|
let agentsToResolve = teamConfig.agents || [];
|
||||||
|
|
@ -78,7 +78,7 @@ class DependencyResolver {
|
||||||
if (agentsToResolve.includes('*')) {
|
if (agentsToResolve.includes('*')) {
|
||||||
const allAgents = await this.listAgents();
|
const allAgents = await this.listAgents();
|
||||||
// Remove wildcard and add all agents except those already in the list and bmad-master
|
// Remove wildcard and add all agents except those already in the list and bmad-master
|
||||||
agentsToResolve = agentsToResolve.filter(a => a !== '*');
|
agentsToResolve = agentsToResolve.filter((a) => a !== '*');
|
||||||
for (const agent of allAgents) {
|
for (const agent of allAgents) {
|
||||||
if (!agentsToResolve.includes(agent) && agent !== 'bmad-master') {
|
if (!agentsToResolve.includes(agent) && agent !== 'bmad-master') {
|
||||||
agentsToResolve.push(agent);
|
agentsToResolve.push(agent);
|
||||||
|
|
@ -92,9 +92,9 @@ class DependencyResolver {
|
||||||
dependencies.agents.push(agentDeps.agent);
|
dependencies.agents.push(agentDeps.agent);
|
||||||
|
|
||||||
// Add resources with deduplication
|
// Add resources with deduplication
|
||||||
agentDeps.resources.forEach(res => {
|
for (const res of agentDeps.resources) {
|
||||||
dependencies.resources.set(res.path, res);
|
dependencies.resources.set(res.path, res);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve workflows
|
// Resolve workflows
|
||||||
|
|
@ -104,7 +104,7 @@ class DependencyResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Map back to array
|
// Convert Map back to array
|
||||||
dependencies.resources = Array.from(dependencies.resources.values());
|
dependencies.resources = [...dependencies.resources.values()];
|
||||||
|
|
||||||
return dependencies;
|
return dependencies;
|
||||||
}
|
}
|
||||||
|
|
@ -123,12 +123,12 @@ class DependencyResolver {
|
||||||
try {
|
try {
|
||||||
filePath = path.join(this.bmadCore, type, id);
|
filePath = path.join(this.bmadCore, type, id);
|
||||||
content = await fs.readFile(filePath, 'utf8');
|
content = await fs.readFile(filePath, 'utf8');
|
||||||
} catch (e) {
|
} catch {
|
||||||
// If not found in bmad-core, try common folder
|
// If not found in bmad-core, try common folder
|
||||||
try {
|
try {
|
||||||
filePath = path.join(this.common, type, id);
|
filePath = path.join(this.common, type, id);
|
||||||
content = await fs.readFile(filePath, 'utf8');
|
content = await fs.readFile(filePath, 'utf8');
|
||||||
} catch (e2) {
|
} catch {
|
||||||
// File not found in either location
|
// File not found in either location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +142,7 @@ class DependencyResolver {
|
||||||
type,
|
type,
|
||||||
id,
|
id,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
content
|
content,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.cache.set(cacheKey, resource);
|
this.cache.set(cacheKey, resource);
|
||||||
|
|
@ -156,10 +156,8 @@ class DependencyResolver {
|
||||||
async listAgents() {
|
async listAgents() {
|
||||||
try {
|
try {
|
||||||
const files = await fs.readdir(path.join(this.bmadCore, 'agents'));
|
const files = await fs.readdir(path.join(this.bmadCore, 'agents'));
|
||||||
return files
|
return files.filter((f) => f.endsWith('.md')).map((f) => f.replace('.md', ''));
|
||||||
.filter(f => f.endsWith('.md'))
|
} catch {
|
||||||
.map(f => f.replace('.md', ''));
|
|
||||||
} catch (error) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,10 +165,8 @@ class DependencyResolver {
|
||||||
async listTeams() {
|
async listTeams() {
|
||||||
try {
|
try {
|
||||||
const files = await fs.readdir(path.join(this.bmadCore, 'agent-teams'));
|
const files = await fs.readdir(path.join(this.bmadCore, 'agent-teams'));
|
||||||
return files
|
return files.filter((f) => f.endsWith('.yaml')).map((f) => f.replace('.yaml', ''));
|
||||||
.filter(f => f.endsWith('.yaml'))
|
} catch {
|
||||||
.map(f => f.replace('.yaml', ''));
|
|
||||||
} catch (error) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
*/
|
*/
|
||||||
function extractYamlFromAgent(agentContent, cleanCommands = false) {
|
function extractYamlFromAgent(agentContent, cleanCommands = false) {
|
||||||
// Remove carriage returns and match YAML block
|
// Remove carriage returns and match YAML block
|
||||||
const yamlMatch = agentContent.replace(/\r/g, "").match(/```ya?ml\n([\s\S]*?)\n```/);
|
const yamlMatch = agentContent.replaceAll('\r', '').match(/```ya?ml\n([\s\S]*?)\n```/);
|
||||||
if (!yamlMatch) return null;
|
if (!yamlMatch) return null;
|
||||||
|
|
||||||
let yamlContent = yamlMatch[1].trim();
|
let yamlContent = yamlMatch[1].trim();
|
||||||
|
|
@ -18,12 +18,12 @@ function extractYamlFromAgent(agentContent, cleanCommands = false) {
|
||||||
// Clean up command descriptions if requested
|
// Clean up command descriptions if requested
|
||||||
// Converts "- command - description" to just "- command"
|
// Converts "- command - description" to just "- command"
|
||||||
if (cleanCommands) {
|
if (cleanCommands) {
|
||||||
yamlContent = yamlContent.replace(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
|
yamlContent = yamlContent.replaceAll(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
|
||||||
}
|
}
|
||||||
|
|
||||||
return yamlContent;
|
return yamlContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extractYamlFromAgent
|
extractYamlFromAgent,
|
||||||
};
|
};
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
* Semantic-release plugin to sync installer package.json version
|
* Semantic-release plugin to sync installer package.json version
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('node:fs');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
|
|
||||||
// This function runs during the "prepare" step of semantic-release
|
// This function runs during the "prepare" step of semantic-release
|
||||||
function prepare(_, { nextRelease, logger }) {
|
function prepare(_, { nextRelease, logger }) {
|
||||||
|
|
@ -14,13 +14,13 @@ function prepare(_, { nextRelease, logger }) {
|
||||||
if (!fs.existsSync(file)) return logger.log('Installer package.json not found, skipping');
|
if (!fs.existsSync(file)) return logger.log('Installer package.json not found, skipping');
|
||||||
|
|
||||||
// Read and parse the package.json file
|
// Read and parse the package.json file
|
||||||
const pkg = JSON.parse(fs.readFileSync(file, 'utf8'));
|
const package_ = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||||
|
|
||||||
// Update the version field with the next release version
|
// Update the version field with the next release version
|
||||||
pkg.version = nextRelease.version;
|
package_.version = nextRelease.version;
|
||||||
|
|
||||||
// Write the updated JSON back to the file
|
// Write the updated JSON back to the file
|
||||||
fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + '\n');
|
fs.writeFileSync(file, JSON.stringify(package_, null, 2) + '\n');
|
||||||
|
|
||||||
// Log success message
|
// Log success message
|
||||||
logger.log(`Synced installer package.json to version ${nextRelease.version}`);
|
logger.log(`Synced installer package.json to version ${nextRelease.version}`);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// ASCII banner art definitions extracted from banners.js to separate art from logic
|
// ASCII banner art definitions extracted from banners.js to separate art from logic
|
||||||
|
|
||||||
const BMAD_TITLE = "BMAD-METHOD";
|
const BMAD_TITLE = 'BMAD-METHOD';
|
||||||
const FLATTENER_TITLE = "FLATTENER";
|
const FLATTENER_TITLE = 'FLATTENER';
|
||||||
const INSTALLER_TITLE = "INSTALLER";
|
const INSTALLER_TITLE = 'INSTALLER';
|
||||||
|
|
||||||
// Large ASCII blocks (block-style fonts)
|
// Large ASCII blocks (block-style fonts)
|
||||||
const BMAD_LARGE = `
|
const BMAD_LARGE = `
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync installer package.json version with main package.json
|
* Sync installer package.json version with main package.json
|
||||||
* Used by semantic-release to keep versions in sync
|
* Used by semantic-release to keep versions in sync
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('node:fs');
|
||||||
const path = require('path');
|
const path = require('node:path');
|
||||||
|
|
||||||
function syncInstallerVersion() {
|
function syncInstallerVersion() {
|
||||||
// Read main package.json
|
// Read main package.json
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue