bmad-method 4.30.2 → 4.30.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +1 -1
- package/bmad-core/core-config.yaml +0 -1
- package/dist/agents/analyst.txt +1 -1
- package/dist/agents/bmad-master.txt +1 -1
- package/dist/agents/bmad-orchestrator.txt +1 -1
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +2409 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +1480 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +826 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +10690 -0
- package/dist/teams/team-all.txt +1 -1
- package/dist/teams/team-fullstack.txt +1 -1
- package/dist/teams/team-ide-minimal.txt +1 -1
- package/dist/teams/team-no-ui.txt +1 -1
- package/docs/bmad-workflow-guide.md +1 -1
- package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +2 -2
- package/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +13 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +72 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +78 -0
- package/expansion-packs/{bmad-creator-tools/agents/bmad-the-creator.md → bmad-2d-unity-game-dev/agents/game-sm.md} +26 -28
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +201 -0
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +160 -0
- package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +6 -0
- package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +251 -0
- package/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +590 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +111 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +217 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +308 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +545 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +356 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +343 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +256 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +484 -0
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +183 -0
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +175 -0
- package/expansion-packs/bmad-infrastructure-devops/config.yaml +2 -2
- package/package.json +4 -8
- package/tools/bump-all-versions.js +8 -9
- package/tools/bump-expansion-version.js +40 -35
- package/tools/installer/bin/bmad.js +8 -21
- package/tools/installer/lib/file-manager.js +76 -44
- package/tools/installer/lib/ide-base-setup.js +227 -0
- package/tools/installer/lib/ide-setup.js +8 -58
- package/tools/installer/lib/installer.js +99 -121
- package/tools/installer/lib/memory-profiler.js +224 -0
- package/tools/installer/lib/module-manager.js +110 -0
- package/tools/installer/lib/resource-locator.js +310 -0
- package/tools/installer/package.json +1 -1
- package/tools/semantic-release-sync-installer.js +20 -21
- package/dist/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.txt +0 -2008
- package/expansion-packs/bmad-creator-tools/README.md +0 -8
- package/expansion-packs/bmad-creator-tools/config.yaml +0 -6
- package/expansion-packs/bmad-creator-tools/tasks/create-agent.md +0 -200
- package/expansion-packs/bmad-creator-tools/tasks/generate-expansion-pack.md +0 -1020
- package/expansion-packs/bmad-creator-tools/templates/agent-teams-tmpl.yaml +0 -178
- package/expansion-packs/bmad-creator-tools/templates/agent-tmpl.yaml +0 -154
- package/expansion-packs/bmad-creator-tools/templates/expansion-pack-plan-tmpl.yaml +0 -120
- package/tools/bump-core-version.js +0 -57
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
workflow:
|
|
2
|
+
id: unity-game-prototype
|
|
3
|
+
name: Game Prototype Development (Unity)
|
|
4
|
+
description: Fast-track workflow for rapid game prototyping and concept validation. Optimized for game jams, proof-of-concept development, and quick iteration on game mechanics using Unity and C#.
|
|
5
|
+
type: prototype
|
|
6
|
+
project_types:
|
|
7
|
+
- game-jam
|
|
8
|
+
- proof-of-concept
|
|
9
|
+
- mechanic-test
|
|
10
|
+
- technical-demo
|
|
11
|
+
- learning-project
|
|
12
|
+
- rapid-iteration
|
|
13
|
+
prototype_sequence:
|
|
14
|
+
- step: concept_definition
|
|
15
|
+
agent: game-designer
|
|
16
|
+
duration: 15-30 minutes
|
|
17
|
+
creates: concept-summary.md
|
|
18
|
+
notes: Quickly define core game concept, primary mechanic, and target experience. Focus on what makes this game unique and fun.
|
|
19
|
+
- step: rapid_design
|
|
20
|
+
agent: game-designer
|
|
21
|
+
duration: 30-60 minutes
|
|
22
|
+
creates: prototype-spec.md
|
|
23
|
+
requires: concept-summary.md
|
|
24
|
+
optional_steps:
|
|
25
|
+
- quick_brainstorming
|
|
26
|
+
- reference_research
|
|
27
|
+
notes: Create minimal but complete design specification. Focus on core mechanics, basic controls, and success/failure conditions.
|
|
28
|
+
- step: technical_planning
|
|
29
|
+
agent: game-developer
|
|
30
|
+
duration: 15-30 minutes
|
|
31
|
+
creates: prototype-architecture.md
|
|
32
|
+
requires: prototype-spec.md
|
|
33
|
+
notes: Define minimal technical implementation plan. Identify core Unity systems needed and performance constraints.
|
|
34
|
+
- step: implementation_stories
|
|
35
|
+
agent: game-sm
|
|
36
|
+
duration: 30-45 minutes
|
|
37
|
+
creates: prototype-stories/
|
|
38
|
+
requires: prototype-spec.md, prototype-architecture.md
|
|
39
|
+
notes: Create 3-5 focused implementation stories for core prototype features. Each story should be completable in 2-4 hours.
|
|
40
|
+
- step: iterative_development
|
|
41
|
+
agent: game-developer
|
|
42
|
+
duration: varies
|
|
43
|
+
implements: prototype-stories/
|
|
44
|
+
notes: Implement stories in priority order. Test frequently in the Unity Editor and adjust design based on what feels fun. Document discoveries.
|
|
45
|
+
workflow_end:
|
|
46
|
+
action: prototype_evaluation
|
|
47
|
+
notes: 'Prototype complete. Evaluate core mechanics, gather feedback, and decide next steps: iterate, expand, or archive.'
|
|
48
|
+
game_jam_sequence:
|
|
49
|
+
- step: jam_concept
|
|
50
|
+
agent: game-designer
|
|
51
|
+
duration: 10-15 minutes
|
|
52
|
+
creates: jam-concept.md
|
|
53
|
+
notes: Define game concept based on jam theme. One sentence core mechanic, basic controls, win condition.
|
|
54
|
+
- step: jam_implementation
|
|
55
|
+
agent: game-developer
|
|
56
|
+
duration: varies (jam timeline)
|
|
57
|
+
creates: working-prototype
|
|
58
|
+
requires: jam-concept.md
|
|
59
|
+
notes: Directly implement core mechanic in Unity. No formal stories - iterate rapidly on what's fun. Document major decisions.
|
|
60
|
+
jam_workflow_end:
|
|
61
|
+
action: jam_submission
|
|
62
|
+
notes: Submit to game jam. Capture lessons learned and consider post-jam development if concept shows promise.
|
|
63
|
+
flow_diagram: |
|
|
64
|
+
```mermaid
|
|
65
|
+
graph TD
|
|
66
|
+
A[Start: Prototype Project] --> B{Development Context?}
|
|
67
|
+
B -->|Standard Prototype| C[game-designer: concept-summary.md]
|
|
68
|
+
B -->|Game Jam| D[game-designer: jam-concept.md]
|
|
69
|
+
|
|
70
|
+
C --> E[game-designer: prototype-spec.md]
|
|
71
|
+
E --> F[game-developer: prototype-architecture.md]
|
|
72
|
+
F --> G[game-sm: create prototype stories]
|
|
73
|
+
G --> H[game-developer: iterative implementation]
|
|
74
|
+
H --> I[Prototype Evaluation]
|
|
75
|
+
|
|
76
|
+
D --> J[game-developer: direct implementation]
|
|
77
|
+
J --> K[Game Jam Submission]
|
|
78
|
+
|
|
79
|
+
E -.-> E1[Optional: quick brainstorming]
|
|
80
|
+
E -.-> E2[Optional: reference research]
|
|
81
|
+
|
|
82
|
+
style I fill:#90EE90
|
|
83
|
+
style K fill:#90EE90
|
|
84
|
+
style C fill:#FFE4B5
|
|
85
|
+
style E fill:#FFE4B5
|
|
86
|
+
style F fill:#FFE4B5
|
|
87
|
+
style G fill:#FFE4B5
|
|
88
|
+
style H fill:#FFE4B5
|
|
89
|
+
style D fill:#FFB6C1
|
|
90
|
+
style J fill:#FFB6C1
|
|
91
|
+
```
|
|
92
|
+
decision_guidance:
|
|
93
|
+
use_prototype_sequence_when:
|
|
94
|
+
- Learning new game development concepts
|
|
95
|
+
- Testing specific game mechanics
|
|
96
|
+
- Building portfolio pieces
|
|
97
|
+
- Have 1-7 days for development
|
|
98
|
+
- Need structured but fast development
|
|
99
|
+
- Want to validate game concepts before full development
|
|
100
|
+
use_game_jam_sequence_when:
|
|
101
|
+
- Participating in time-constrained game jams
|
|
102
|
+
- Have 24-72 hours total development time
|
|
103
|
+
- Want to experiment with wild or unusual concepts
|
|
104
|
+
- Learning through rapid iteration
|
|
105
|
+
- Building networking/portfolio presence
|
|
106
|
+
prototype_best_practices:
|
|
107
|
+
scope_management:
|
|
108
|
+
- Start with absolute minimum viable gameplay
|
|
109
|
+
- One core mechanic implemented well beats many mechanics poorly
|
|
110
|
+
- Focus on "game feel" over features
|
|
111
|
+
- Cut features ruthlessly to meet timeline
|
|
112
|
+
rapid_iteration:
|
|
113
|
+
- Test the game every 1-2 hours of development in the Unity Editor
|
|
114
|
+
- Ask "Is this fun?" frequently during development
|
|
115
|
+
- Be willing to pivot mechanics if they don't feel good
|
|
116
|
+
- Document what works and what doesn't
|
|
117
|
+
technical_efficiency:
|
|
118
|
+
- Use simple graphics (geometric shapes, basic sprites)
|
|
119
|
+
- Leverage Unity's built-in components heavily
|
|
120
|
+
- Avoid complex custom systems in prototypes
|
|
121
|
+
- Prioritize functional over polished
|
|
122
|
+
prototype_evaluation_criteria:
|
|
123
|
+
core_mechanic_validation:
|
|
124
|
+
- Is the primary mechanic engaging for 30+ seconds?
|
|
125
|
+
- Do players understand the mechanic without explanation?
|
|
126
|
+
- Does the mechanic have depth for extended play?
|
|
127
|
+
- Are there natural difficulty progression opportunities?
|
|
128
|
+
technical_feasibility:
|
|
129
|
+
- Does the prototype run at acceptable frame rates?
|
|
130
|
+
- Are there obvious technical blockers for expansion?
|
|
131
|
+
- Is the codebase clean enough for further development?
|
|
132
|
+
- Are performance targets realistic for full game?
|
|
133
|
+
player_experience:
|
|
134
|
+
- Do testers engage with the game voluntarily?
|
|
135
|
+
- What emotions does the game create in players?
|
|
136
|
+
- Are players asking for "just one more try"?
|
|
137
|
+
- What do players want to see added or changed?
|
|
138
|
+
post_prototype_options:
|
|
139
|
+
iterate_and_improve:
|
|
140
|
+
action: continue_prototyping
|
|
141
|
+
when: Core mechanic shows promise but needs refinement
|
|
142
|
+
next_steps: Create new prototype iteration focusing on identified improvements
|
|
143
|
+
expand_to_full_game:
|
|
144
|
+
action: transition_to_full_development
|
|
145
|
+
when: Prototype validates strong game concept
|
|
146
|
+
next_steps: Use game-dev-greenfield workflow to create full game design and architecture
|
|
147
|
+
pivot_concept:
|
|
148
|
+
action: new_prototype_direction
|
|
149
|
+
when: Current mechanic doesn't work but insights suggest new direction
|
|
150
|
+
next_steps: Apply learnings to new prototype concept
|
|
151
|
+
archive_and_learn:
|
|
152
|
+
action: document_learnings
|
|
153
|
+
when: Prototype doesn't work but provides valuable insights
|
|
154
|
+
next_steps: Document lessons learned and move to next prototype concept
|
|
155
|
+
time_boxing_guidance:
|
|
156
|
+
concept_phase: Maximum 30 minutes - if you can't explain the game simply, simplify it
|
|
157
|
+
design_phase: Maximum 1 hour - focus on core mechanics only
|
|
158
|
+
planning_phase: Maximum 30 minutes - identify critical path to playable prototype
|
|
159
|
+
implementation_phase: Time-boxed iterations - test every 2-4 hours of work
|
|
160
|
+
success_metrics:
|
|
161
|
+
development_velocity:
|
|
162
|
+
- Playable prototype in first day of development
|
|
163
|
+
- Core mechanic demonstrable within 4-6 hours of coding
|
|
164
|
+
- Major iteration cycles completed in 2-4 hour blocks
|
|
165
|
+
learning_objectives:
|
|
166
|
+
- Clear understanding of what makes the mechanic fun (or not)
|
|
167
|
+
- Technical feasibility assessment for full development
|
|
168
|
+
- Player reaction and engagement validation
|
|
169
|
+
- Design insights for future development
|
|
170
|
+
handoff_prompts:
|
|
171
|
+
concept_to_design: Game concept defined. Create minimal design specification focusing on core mechanics and player experience.
|
|
172
|
+
design_to_technical: Design specification ready. Create technical implementation plan for rapid prototyping.
|
|
173
|
+
technical_to_stories: Technical plan complete. Create focused implementation stories for prototype development.
|
|
174
|
+
stories_to_implementation: Stories ready. Begin iterative implementation with frequent playtesting and design validation.
|
|
175
|
+
prototype_to_evaluation: Prototype playable. Evaluate core mechanics, gather feedback, and determine next development steps.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
name: bmad-infrastructure-devops
|
|
2
|
-
version: 1.
|
|
3
|
-
short-title: Infrastructure
|
|
2
|
+
version: 1.10.0
|
|
3
|
+
short-title: Infrastructure DevOps Pack
|
|
4
4
|
description: >-
|
|
5
5
|
This expansion pack extends BMad Method with comprehensive infrastructure and
|
|
6
6
|
DevOps capabilities. It's designed for teams that need to define, implement,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bmad-method",
|
|
3
|
-
"version": "4.30.
|
|
3
|
+
"version": "4.30.3",
|
|
4
4
|
"description": "Breakthrough Method of Agile AI-driven Development",
|
|
5
5
|
"main": "tools/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"version:patch": "node tools/version-bump.js patch",
|
|
19
19
|
"version:minor": "node tools/version-bump.js minor",
|
|
20
20
|
"version:major": "node tools/version-bump.js major",
|
|
21
|
-
"version:core": "node tools/bump-core-version.js",
|
|
22
|
-
"version:core:major": "node tools/bump-core-version.js major",
|
|
23
|
-
"version:core:minor": "node tools/bump-core-version.js minor",
|
|
24
|
-
"version:core:patch": "node tools/bump-core-version.js patch",
|
|
25
21
|
"version:expansion": "node tools/bump-expansion-version.js",
|
|
26
22
|
"version:expansion:set": "node tools/update-expansion-version.js",
|
|
27
23
|
"version:all": "node tools/bump-all-versions.js",
|
|
@@ -38,13 +34,13 @@
|
|
|
38
34
|
},
|
|
39
35
|
"dependencies": {
|
|
40
36
|
"@kayvan/markdown-tree-parser": "^1.5.0",
|
|
41
|
-
"chalk": "^
|
|
37
|
+
"chalk": "^4.1.2",
|
|
42
38
|
"commander": "^14.0.0",
|
|
43
39
|
"fs-extra": "^11.3.0",
|
|
44
40
|
"glob": "^11.0.3",
|
|
45
|
-
"inquirer": "^
|
|
41
|
+
"inquirer": "^8.2.6",
|
|
46
42
|
"js-yaml": "^4.1.0",
|
|
47
|
-
"ora": "^
|
|
43
|
+
"ora": "^5.4.1"
|
|
48
44
|
},
|
|
49
45
|
"keywords": [
|
|
50
46
|
"agile",
|
|
@@ -31,21 +31,20 @@ function bumpVersion(currentVersion, type) {
|
|
|
31
31
|
async function bumpAllVersions() {
|
|
32
32
|
const updatedItems = [];
|
|
33
33
|
|
|
34
|
-
// First, bump the core version
|
|
35
|
-
const
|
|
34
|
+
// First, bump the core version (package.json)
|
|
35
|
+
const packagePath = path.join(__dirname, '..', 'package.json');
|
|
36
36
|
try {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const oldCoreVersion =
|
|
37
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
38
|
+
const packageJson = JSON.parse(packageContent);
|
|
39
|
+
const oldCoreVersion = packageJson.version || '1.0.0';
|
|
40
40
|
const newCoreVersion = bumpVersion(oldCoreVersion, bumpType);
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
packageJson.version = newCoreVersion;
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
fs.writeFileSync(coreConfigPath, updatedCoreYaml);
|
|
44
|
+
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
46
45
|
|
|
47
46
|
updatedItems.push({ type: 'core', name: 'BMad Core', oldVersion: oldCoreVersion, newVersion: newCoreVersion });
|
|
48
|
-
console.log(`✓ BMad Core: ${oldCoreVersion} → ${newCoreVersion}`);
|
|
47
|
+
console.log(`✓ BMad Core (package.json): ${oldCoreVersion} → ${newCoreVersion}`);
|
|
49
48
|
} catch (error) {
|
|
50
49
|
console.error(`✗ Failed to update BMad Core: ${error.message}`);
|
|
51
50
|
}
|
|
@@ -1,78 +1,83 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// Load required modules
|
|
3
4
|
const fs = require('fs');
|
|
4
5
|
const path = require('path');
|
|
5
6
|
const yaml = require('js-yaml');
|
|
6
7
|
|
|
8
|
+
// Parse CLI arguments
|
|
7
9
|
const args = process.argv.slice(2);
|
|
10
|
+
const packId = args[0];
|
|
11
|
+
const bumpType = args[1] || 'minor';
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
// Validate arguments
|
|
14
|
+
if (!packId || args.length > 2) {
|
|
10
15
|
console.log('Usage: node bump-expansion-version.js <expansion-pack-id> [major|minor|patch]');
|
|
11
16
|
console.log('Default: minor');
|
|
12
17
|
console.log('Example: node bump-expansion-version.js bmad-creator-tools patch');
|
|
13
18
|
process.exit(1);
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
const packId = args[0];
|
|
17
|
-
const bumpType = args[1] || 'minor'; // default to minor
|
|
18
|
-
|
|
19
21
|
if (!['major', 'minor', 'patch'].includes(bumpType)) {
|
|
20
22
|
console.error('Error: Bump type must be major, minor, or patch');
|
|
21
23
|
process.exit(1);
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
// Version bump logic
|
|
24
27
|
function bumpVersion(currentVersion, type) {
|
|
25
28
|
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
|
26
|
-
|
|
29
|
+
|
|
27
30
|
switch (type) {
|
|
28
|
-
case 'major':
|
|
29
|
-
|
|
30
|
-
case '
|
|
31
|
-
|
|
32
|
-
case 'patch':
|
|
33
|
-
return `${major}.${minor}.${patch + 1}`;
|
|
34
|
-
default:
|
|
35
|
-
return currentVersion;
|
|
31
|
+
case 'major': return `${major + 1}.0.0`;
|
|
32
|
+
case 'minor': return `${major}.${minor + 1}.0`;
|
|
33
|
+
case 'patch': return `${major}.${minor}.${patch + 1}`;
|
|
34
|
+
default: return currentVersion;
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
// Main function to bump version
|
|
39
39
|
async function updateVersion() {
|
|
40
|
+
const configPath = path.join(__dirname, '..', 'expansion-packs', packId, 'config.yaml');
|
|
41
|
+
|
|
42
|
+
// Check if config exists
|
|
43
|
+
if (!fs.existsSync(configPath)) {
|
|
44
|
+
console.error(`Error: Expansion pack '${packId}' not found`);
|
|
45
|
+
console.log('\nAvailable expansion packs:');
|
|
46
|
+
|
|
47
|
+
const packsDir = path.join(__dirname, '..', 'expansion-packs');
|
|
48
|
+
const entries = fs.readdirSync(packsDir, { withFileTypes: true });
|
|
49
|
+
|
|
50
|
+
entries.forEach(entry => {
|
|
51
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
52
|
+
console.log(` - ${entry.name}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
40
59
|
try {
|
|
41
|
-
const configPath = path.join(__dirname, '..', 'expansion-packs', packId, 'config.yaml');
|
|
42
|
-
|
|
43
|
-
if (!fs.existsSync(configPath)) {
|
|
44
|
-
console.error(`Error: Expansion pack '${packId}' not found`);
|
|
45
|
-
console.log('\nAvailable expansion packs:');
|
|
46
|
-
const expansionPacksDir = path.join(__dirname, '..', 'expansion-packs');
|
|
47
|
-
const entries = fs.readdirSync(expansionPacksDir, { withFileTypes: true });
|
|
48
|
-
entries.forEach(entry => {
|
|
49
|
-
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
50
|
-
console.log(` - ${entry.name}`);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
60
|
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
57
61
|
const config = yaml.load(configContent);
|
|
62
|
+
|
|
58
63
|
const oldVersion = config.version || '1.0.0';
|
|
59
64
|
const newVersion = bumpVersion(oldVersion, bumpType);
|
|
60
|
-
|
|
65
|
+
|
|
61
66
|
config.version = newVersion;
|
|
62
|
-
|
|
67
|
+
|
|
63
68
|
const updatedYaml = yaml.dump(config, { indent: 2 });
|
|
64
69
|
fs.writeFileSync(configPath, updatedYaml);
|
|
65
|
-
|
|
70
|
+
|
|
66
71
|
console.log(`✓ ${packId}: ${oldVersion} → ${newVersion}`);
|
|
67
72
|
console.log(`\n✓ Successfully bumped ${packId} with ${bumpType} version bump`);
|
|
68
73
|
console.log('\nNext steps:');
|
|
69
|
-
console.log(
|
|
70
|
-
console.log(
|
|
71
|
-
|
|
74
|
+
console.log(`1. Test the changes`);
|
|
75
|
+
console.log(`2. Commit: git add -A && git commit -m "chore: bump ${packId} version (${bumpType})"`);
|
|
76
|
+
|
|
72
77
|
} catch (error) {
|
|
73
78
|
console.error('Error updating version:', error.message);
|
|
74
79
|
process.exit(1);
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
updateVersion();
|
|
83
|
+
updateVersion();
|
|
@@ -4,17 +4,8 @@ const { program } = require('commander');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const fs = require('fs').promises;
|
|
6
6
|
const yaml = require('js-yaml');
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let chalk, inquirer;
|
|
10
|
-
|
|
11
|
-
// Initialize ES modules
|
|
12
|
-
async function initializeModules() {
|
|
13
|
-
if (!chalk) {
|
|
14
|
-
chalk = (await import('chalk')).default;
|
|
15
|
-
inquirer = (await import('inquirer')).default;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const inquirer = require('inquirer');
|
|
18
9
|
|
|
19
10
|
// Handle both execution contexts (from root via npx or from installer directory)
|
|
20
11
|
let version;
|
|
@@ -54,12 +45,12 @@ program
|
|
|
54
45
|
.option('-e, --expansion-packs <packs...>', 'Install specific expansion packs (can specify multiple)')
|
|
55
46
|
.action(async (options) => {
|
|
56
47
|
try {
|
|
57
|
-
await initializeModules();
|
|
58
48
|
if (!options.full && !options.expansionOnly) {
|
|
59
49
|
// Interactive mode
|
|
60
50
|
const answers = await promptInstallation();
|
|
61
51
|
if (!answers._alreadyInstalled) {
|
|
62
52
|
await installer.install(answers);
|
|
53
|
+
process.exit(0);
|
|
63
54
|
}
|
|
64
55
|
} else {
|
|
65
56
|
// Direct mode
|
|
@@ -73,9 +64,9 @@ program
|
|
|
73
64
|
expansionPacks: options.expansionPacks || []
|
|
74
65
|
};
|
|
75
66
|
await installer.install(config);
|
|
67
|
+
process.exit(0);
|
|
76
68
|
}
|
|
77
69
|
} catch (error) {
|
|
78
|
-
if (!chalk) await initializeModules();
|
|
79
70
|
console.error(chalk.red('Installation failed:'), error.message);
|
|
80
71
|
process.exit(1);
|
|
81
72
|
}
|
|
@@ -90,7 +81,6 @@ program
|
|
|
90
81
|
try {
|
|
91
82
|
await installer.update();
|
|
92
83
|
} catch (error) {
|
|
93
|
-
if (!chalk) await initializeModules();
|
|
94
84
|
console.error(chalk.red('Update failed:'), error.message);
|
|
95
85
|
process.exit(1);
|
|
96
86
|
}
|
|
@@ -103,7 +93,6 @@ program
|
|
|
103
93
|
try {
|
|
104
94
|
await installer.listExpansionPacks();
|
|
105
95
|
} catch (error) {
|
|
106
|
-
if (!chalk) await initializeModules();
|
|
107
96
|
console.error(chalk.red('Error:'), error.message);
|
|
108
97
|
process.exit(1);
|
|
109
98
|
}
|
|
@@ -116,14 +105,12 @@ program
|
|
|
116
105
|
try {
|
|
117
106
|
await installer.showStatus();
|
|
118
107
|
} catch (error) {
|
|
119
|
-
if (!chalk) await initializeModules();
|
|
120
108
|
console.error(chalk.red('Error:'), error.message);
|
|
121
109
|
process.exit(1);
|
|
122
110
|
}
|
|
123
111
|
});
|
|
124
112
|
|
|
125
113
|
async function promptInstallation() {
|
|
126
|
-
await initializeModules();
|
|
127
114
|
|
|
128
115
|
// Display ASCII logo
|
|
129
116
|
console.log(chalk.bold.cyan(`
|
|
@@ -178,13 +165,13 @@ async function promptInstallation() {
|
|
|
178
165
|
let bmadOptionText;
|
|
179
166
|
if (state.type === 'v4_existing') {
|
|
180
167
|
const currentVersion = state.manifest?.version || 'unknown';
|
|
181
|
-
const newVersion =
|
|
168
|
+
const newVersion = version; // Always use package.json version
|
|
182
169
|
const versionInfo = currentVersion === newVersion
|
|
183
170
|
? `(v${currentVersion} - reinstall)`
|
|
184
171
|
: `(v${currentVersion} → v${newVersion})`;
|
|
185
172
|
bmadOptionText = `Update ${coreShortTitle} ${versionInfo} .bmad-core`;
|
|
186
173
|
} else {
|
|
187
|
-
bmadOptionText =
|
|
174
|
+
bmadOptionText = `${coreShortTitle} (v${version}) .bmad-core`;
|
|
188
175
|
}
|
|
189
176
|
|
|
190
177
|
choices.push({
|
|
@@ -204,9 +191,9 @@ async function promptInstallation() {
|
|
|
204
191
|
const versionInfo = currentVersion === newVersion
|
|
205
192
|
? `(v${currentVersion} - reinstall)`
|
|
206
193
|
: `(v${currentVersion} → v${newVersion})`;
|
|
207
|
-
packOptionText = `Update ${pack.
|
|
194
|
+
packOptionText = `Update ${pack.shortTitle} ${versionInfo} .${pack.id}`;
|
|
208
195
|
} else {
|
|
209
|
-
packOptionText =
|
|
196
|
+
packOptionText = `${pack.shortTitle} (v${pack.version}) .${pack.id}`;
|
|
210
197
|
}
|
|
211
198
|
|
|
212
199
|
choices.push({
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
const fs = require("fs-extra");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const crypto = require("crypto");
|
|
4
|
-
const glob = require("glob");
|
|
5
4
|
const yaml = require("js-yaml");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Initialize ES modules
|
|
11
|
-
async function initializeModules() {
|
|
12
|
-
if (!chalk) {
|
|
13
|
-
chalk = (await import("chalk")).default;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const { createReadStream, createWriteStream, promises: fsPromises } = require('fs');
|
|
7
|
+
const { pipeline } = require('stream/promises');
|
|
8
|
+
const resourceLocator = require('./resource-locator');
|
|
16
9
|
|
|
17
10
|
class FileManager {
|
|
18
11
|
constructor() {
|
|
@@ -23,10 +16,19 @@ class FileManager {
|
|
|
23
16
|
async copyFile(source, destination) {
|
|
24
17
|
try {
|
|
25
18
|
await fs.ensureDir(path.dirname(destination));
|
|
26
|
-
|
|
19
|
+
|
|
20
|
+
// Use streaming for large files (> 10MB)
|
|
21
|
+
const stats = await fs.stat(source);
|
|
22
|
+
if (stats.size > 10 * 1024 * 1024) {
|
|
23
|
+
await pipeline(
|
|
24
|
+
createReadStream(source),
|
|
25
|
+
createWriteStream(destination)
|
|
26
|
+
);
|
|
27
|
+
} else {
|
|
28
|
+
await fs.copy(source, destination);
|
|
29
|
+
}
|
|
27
30
|
return true;
|
|
28
31
|
} catch (error) {
|
|
29
|
-
await initializeModules();
|
|
30
32
|
console.error(chalk.red(`Failed to copy ${source}:`), error.message);
|
|
31
33
|
return false;
|
|
32
34
|
}
|
|
@@ -35,10 +37,28 @@ class FileManager {
|
|
|
35
37
|
async copyDirectory(source, destination) {
|
|
36
38
|
try {
|
|
37
39
|
await fs.ensureDir(destination);
|
|
38
|
-
|
|
40
|
+
|
|
41
|
+
// Use streaming copy for large directories
|
|
42
|
+
const files = await resourceLocator.findFiles('**/*', {
|
|
43
|
+
cwd: source,
|
|
44
|
+
nodir: true
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Process files in batches to avoid memory issues
|
|
48
|
+
const batchSize = 50;
|
|
49
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
50
|
+
const batch = files.slice(i, i + batchSize);
|
|
51
|
+
await Promise.all(
|
|
52
|
+
batch.map(file =>
|
|
53
|
+
this.copyFile(
|
|
54
|
+
path.join(source, file),
|
|
55
|
+
path.join(destination, file)
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
39
60
|
return true;
|
|
40
61
|
} catch (error) {
|
|
41
|
-
await initializeModules();
|
|
42
62
|
console.error(
|
|
43
63
|
chalk.red(`Failed to copy directory ${source}:`),
|
|
44
64
|
error.message
|
|
@@ -48,7 +68,7 @@ class FileManager {
|
|
|
48
68
|
}
|
|
49
69
|
|
|
50
70
|
async copyGlobPattern(pattern, sourceDir, destDir, rootValue = null) {
|
|
51
|
-
const files =
|
|
71
|
+
const files = await resourceLocator.findFiles(pattern, { cwd: sourceDir });
|
|
52
72
|
const copied = [];
|
|
53
73
|
|
|
54
74
|
for (const file of files) {
|
|
@@ -75,12 +95,15 @@ class FileManager {
|
|
|
75
95
|
|
|
76
96
|
async calculateFileHash(filePath) {
|
|
77
97
|
try {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
98
|
+
// Use streaming for hash calculation to reduce memory usage
|
|
99
|
+
const stream = createReadStream(filePath);
|
|
100
|
+
const hash = crypto.createHash("sha256");
|
|
101
|
+
|
|
102
|
+
for await (const chunk of stream) {
|
|
103
|
+
hash.update(chunk);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return hash.digest("hex").slice(0, 16);
|
|
84
107
|
} catch (error) {
|
|
85
108
|
return null;
|
|
86
109
|
}
|
|
@@ -93,15 +116,14 @@ class FileManager {
|
|
|
93
116
|
this.manifestFile
|
|
94
117
|
);
|
|
95
118
|
|
|
96
|
-
// Read version from
|
|
97
|
-
const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yaml");
|
|
119
|
+
// Read version from package.json
|
|
98
120
|
let coreVersion = "unknown";
|
|
99
121
|
try {
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
coreVersion =
|
|
122
|
+
const packagePath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
123
|
+
const packageJson = require(packagePath);
|
|
124
|
+
coreVersion = packageJson.version;
|
|
103
125
|
} catch (error) {
|
|
104
|
-
console.warn("Could not read version from
|
|
126
|
+
console.warn("Could not read version from package.json, using 'unknown'");
|
|
105
127
|
}
|
|
106
128
|
|
|
107
129
|
const manifest = {
|
|
@@ -304,7 +326,6 @@ class FileManager {
|
|
|
304
326
|
|
|
305
327
|
return true;
|
|
306
328
|
} catch (error) {
|
|
307
|
-
await initializeModules();
|
|
308
329
|
console.error(chalk.red(`Failed to modify core-config.yaml:`), error.message);
|
|
309
330
|
return false;
|
|
310
331
|
}
|
|
@@ -312,22 +333,35 @@ class FileManager {
|
|
|
312
333
|
|
|
313
334
|
async copyFileWithRootReplacement(source, destination, rootValue) {
|
|
314
335
|
try {
|
|
315
|
-
//
|
|
316
|
-
const
|
|
317
|
-
const content = await fs.readFile(source, 'utf8');
|
|
318
|
-
|
|
319
|
-
// Replace {root} with the specified root value
|
|
320
|
-
const updatedContent = content.replace(/\{root\}/g, rootValue);
|
|
336
|
+
// Check file size to determine if we should stream
|
|
337
|
+
const stats = await fs.stat(source);
|
|
321
338
|
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
339
|
+
if (stats.size > 5 * 1024 * 1024) { // 5MB threshold
|
|
340
|
+
// Use streaming for large files
|
|
341
|
+
const { Transform } = require('stream');
|
|
342
|
+
const replaceStream = new Transform({
|
|
343
|
+
transform(chunk, encoding, callback) {
|
|
344
|
+
const modified = chunk.toString().replace(/\{root\}/g, rootValue);
|
|
345
|
+
callback(null, modified);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
await this.ensureDirectory(path.dirname(destination));
|
|
350
|
+
await pipeline(
|
|
351
|
+
createReadStream(source, { encoding: 'utf8' }),
|
|
352
|
+
replaceStream,
|
|
353
|
+
createWriteStream(destination, { encoding: 'utf8' })
|
|
354
|
+
);
|
|
355
|
+
} else {
|
|
356
|
+
// Regular approach for smaller files
|
|
357
|
+
const content = await fsPromises.readFile(source, 'utf8');
|
|
358
|
+
const updatedContent = content.replace(/\{root\}/g, rootValue);
|
|
359
|
+
await this.ensureDirectory(path.dirname(destination));
|
|
360
|
+
await fsPromises.writeFile(destination, updatedContent, 'utf8');
|
|
361
|
+
}
|
|
327
362
|
|
|
328
363
|
return true;
|
|
329
364
|
} catch (error) {
|
|
330
|
-
await initializeModules();
|
|
331
365
|
console.error(chalk.red(`Failed to copy ${source} with root replacement:`), error.message);
|
|
332
366
|
return false;
|
|
333
367
|
}
|
|
@@ -335,11 +369,10 @@ class FileManager {
|
|
|
335
369
|
|
|
336
370
|
async copyDirectoryWithRootReplacement(source, destination, rootValue, fileExtensions = ['.md', '.yaml', '.yml']) {
|
|
337
371
|
try {
|
|
338
|
-
await initializeModules(); // Ensure chalk is initialized
|
|
339
372
|
await this.ensureDirectory(destination);
|
|
340
373
|
|
|
341
374
|
// Get all files in source directory
|
|
342
|
-
const files =
|
|
375
|
+
const files = await resourceLocator.findFiles('**/*', {
|
|
343
376
|
cwd: source,
|
|
344
377
|
nodir: true
|
|
345
378
|
});
|
|
@@ -369,7 +402,6 @@ class FileManager {
|
|
|
369
402
|
|
|
370
403
|
return true;
|
|
371
404
|
} catch (error) {
|
|
372
|
-
await initializeModules();
|
|
373
405
|
console.error(chalk.red(`Failed to copy directory ${source} with root replacement:`), error.message);
|
|
374
406
|
return false;
|
|
375
407
|
}
|