Node 20, installer improvements, agent improvements and Expansion Pack for game dev (#232)
* feat: add expansion pack installation system with game dev and infrastructure expansion packs - Added expansion pack discovery and installation to BMAD installer - Supports interactive and CLI installation of expansion packs - Expansion pack files install to destination root (.bmad-core) - Added game development expansion pack (.bmad-2d-phaser-game-dev) - Game designer, developer, and scrum master agents - Game-specific templates, tasks, workflows, and guidelines - Specialized for Phaser 3 + TypeScript development - Added infrastructure devops expansion pack (.bmad-infrastructure-devops) - Platform engineering agent and infrastructure templates - Expansion pack agents automatically integrate with IDE rules - Added list:expansions command and --expansion-packs CLI option 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * alpha expansion packs and installer update to support installing expansion packs optionally * node20 --------- Co-authored-by: Brian Madison <brianmadison@Brians-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,8 @@ program
|
||||
.option('-f, --full', 'Install complete .bmad-core folder')
|
||||
.option('-a, --agent <agent>', 'Install specific agent with dependencies')
|
||||
.option('-d, --directory <path>', 'Installation directory (default: .bmad-core)')
|
||||
.option('-i, --ide <ide...>', 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, roo)')
|
||||
.option('-i, --ide <ide...>', 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, roo, other)')
|
||||
.option('-e, --expansion-packs <packs...>', 'Install specific expansion packs (can specify multiple)')
|
||||
.action(async (options) => {
|
||||
try {
|
||||
await initializeModules();
|
||||
@@ -61,7 +62,8 @@ program
|
||||
installType: options.full ? 'full' : 'single-agent',
|
||||
agent: options.agent,
|
||||
directory: options.directory || '.bmad-core',
|
||||
ides: options.ide || []
|
||||
ides: (options.ide || []).filter(ide => ide !== 'other'),
|
||||
expansionPacks: options.expansionPacks || []
|
||||
};
|
||||
await installer.install(config);
|
||||
}
|
||||
@@ -100,6 +102,19 @@ program
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command('list:expansions')
|
||||
.description('List available expansion packs')
|
||||
.action(async () => {
|
||||
try {
|
||||
await installer.listExpansionPacks();
|
||||
} catch (error) {
|
||||
if (!chalk) await initializeModules();
|
||||
console.error(chalk.red('Error:'), error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command('status')
|
||||
.description('Show installation status')
|
||||
@@ -167,6 +182,41 @@ async function promptInstallation() {
|
||||
answers.agent = agent;
|
||||
}
|
||||
|
||||
// Ask for expansion pack selection (only for full installation)
|
||||
if (installType === 'full') {
|
||||
try {
|
||||
const availableExpansionPacks = await installer.getAvailableExpansionPacks();
|
||||
|
||||
if (availableExpansionPacks.length > 0) {
|
||||
const { expansionPacks } = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'expansionPacks',
|
||||
message: 'Select expansion packs to install (optional):',
|
||||
choices: [
|
||||
{ name: 'BMAD Core only (no expansion packs)', value: 'none', checked: true },
|
||||
new inquirer.Separator(' --- Expansion Packs ---'),
|
||||
...availableExpansionPacks.map(pack => ({
|
||||
name: `${pack.name} - ${pack.description}`,
|
||||
value: pack.id
|
||||
}))
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
// Filter out 'none' selection and only include actual expansion packs
|
||||
answers.expansionPacks = expansionPacks.filter(pack => pack !== 'none');
|
||||
} else {
|
||||
answers.expansionPacks = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(chalk.yellow('Warning: Could not load expansion packs. Continuing without them.'));
|
||||
answers.expansionPacks = [];
|
||||
}
|
||||
} else {
|
||||
answers.expansionPacks = [];
|
||||
}
|
||||
|
||||
// Ask for IDE configuration
|
||||
const { ides } = await inquirer.prompt([
|
||||
{
|
||||
@@ -177,17 +227,20 @@ async function promptInstallation() {
|
||||
{ name: 'Cursor', value: 'cursor' },
|
||||
{ name: 'Claude Code', value: 'claude-code' },
|
||||
{ name: 'Windsurf', value: 'windsurf' },
|
||||
{ name: 'Roo Code', value: 'roo' }
|
||||
{ name: 'Roo Code', value: 'roo' },
|
||||
{ name: 'Other (skip IDE setup)', value: 'other' }
|
||||
],
|
||||
validate: (answer) => {
|
||||
if (answer.length < 1) {
|
||||
return 'You must choose at least one IDE, or press Ctrl+C to skip IDE setup.';
|
||||
return 'You must choose at least one IDE option.';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
]);
|
||||
answers.ides = ides;
|
||||
|
||||
// Filter out 'other' from the list and only include actual IDEs
|
||||
answers.ides = ides.filter(ide => ide !== 'other');
|
||||
|
||||
return answers;
|
||||
}
|
||||
|
||||
@@ -3,55 +3,55 @@ installation-options:
|
||||
name: Complete BMAD Core
|
||||
description: Copy the entire .bmad-core folder with all agents, templates, and tools
|
||||
action: copy-folder
|
||||
source: .bmad-core
|
||||
source: bmad-core
|
||||
single-agent:
|
||||
name: Single Agent
|
||||
description: Select and install a single agent with its dependencies
|
||||
action: copy-agent
|
||||
agent-dependencies:
|
||||
core-files:
|
||||
- .bmad-core/utils/template-format.md
|
||||
- bmad-core/utils/template-format.md
|
||||
dev:
|
||||
- .bmad-core/templates/story-tmpl.md
|
||||
- .bmad-core/checklists/story-dod-checklist.md
|
||||
- bmad-core/templates/story-tmpl.md
|
||||
- bmad-core/checklists/story-dod-checklist.md
|
||||
pm:
|
||||
- .bmad-core/templates/prd-tmpl.md
|
||||
- .bmad-core/templates/brownfield-prd-tmpl.md
|
||||
- .bmad-core/checklists/pm-checklist.md
|
||||
- .bmad-core/checklists/change-checklist.md
|
||||
- .bmad-core/tasks/advanced-elicitation.md
|
||||
- .bmad-core/tasks/create-doc.md
|
||||
- .bmad-core/tasks/correct-course.md
|
||||
- .bmad-core/tasks/create-deep-research-prompt.md
|
||||
- .bmad-core/tasks/brownfield-create-epic.md
|
||||
- .bmad-core/tasks/brownfield-create-story.md
|
||||
- .bmad-core/tasks/execute-checklist.md
|
||||
- .bmad-core/tasks/shard-doc.md
|
||||
- bmad-core/templates/prd-tmpl.md
|
||||
- bmad-core/templates/brownfield-prd-tmpl.md
|
||||
- bmad-core/checklists/pm-checklist.md
|
||||
- bmad-core/checklists/change-checklist.md
|
||||
- bmad-core/tasks/advanced-elicitation.md
|
||||
- bmad-core/tasks/create-doc.md
|
||||
- bmad-core/tasks/correct-course.md
|
||||
- bmad-core/tasks/create-deep-research-prompt.md
|
||||
- bmad-core/tasks/brownfield-create-epic.md
|
||||
- bmad-core/tasks/brownfield-create-story.md
|
||||
- bmad-core/tasks/execute-checklist.md
|
||||
- bmad-core/tasks/shard-doc.md
|
||||
architect:
|
||||
- .bmad-core/templates/architecture-tmpl.md
|
||||
- .bmad-core/checklists/architect-checklist.md
|
||||
- bmad-core/templates/architecture-tmpl.md
|
||||
- bmad-core/checklists/architect-checklist.md
|
||||
sm:
|
||||
- .bmad-core/templates/story-tmpl.md
|
||||
- .bmad-core/checklists/story-draft-checklist.md
|
||||
- .bmad-core/workflows/*.yml
|
||||
- bmad-core/templates/story-tmpl.md
|
||||
- bmad-core/checklists/story-draft-checklist.md
|
||||
- bmad-core/workflows/*.yml
|
||||
po:
|
||||
- .bmad-core/checklists/po-master-checklist.md
|
||||
- .bmad-core/templates/acceptance-criteria-tmpl.md
|
||||
- bmad-core/checklists/po-master-checklist.md
|
||||
- bmad-core/templates/acceptance-criteria-tmpl.md
|
||||
analyst:
|
||||
- .bmad-core/templates/prd-tmpl.md
|
||||
- .bmad-core/tasks/advanced-elicitation.md
|
||||
- bmad-core/templates/prd-tmpl.md
|
||||
- bmad-core/tasks/advanced-elicitation.md
|
||||
qa:
|
||||
- .bmad-core/checklists/story-dod-checklist.md
|
||||
- .bmad-core/templates/test-plan-tmpl.md
|
||||
- bmad-core/checklists/story-dod-checklist.md
|
||||
- bmad-core/templates/test-plan-tmpl.md
|
||||
ux-expert:
|
||||
- .bmad-core/templates/ux-tmpl.md
|
||||
- bmad-core/templates/ux-tmpl.md
|
||||
bmad-master:
|
||||
- .bmad-core/templates/*.md
|
||||
- .bmad-core/tasks/*.md
|
||||
- .bmad-core/schemas/*.yml
|
||||
- bmad-core/templates/*.md
|
||||
- bmad-core/tasks/*.md
|
||||
- bmad-core/schemas/*.yml
|
||||
bmad-orchestrator:
|
||||
- .bmad-core/agent-teams/*.yml
|
||||
- .bmad-core/workflows/*.yml
|
||||
- bmad-core/agent-teams/*.yml
|
||||
- bmad-core/workflows/*.yml
|
||||
ide-configurations:
|
||||
cursor:
|
||||
name: Cursor
|
||||
@@ -99,41 +99,41 @@ ide-configurations:
|
||||
available-agents:
|
||||
- id: analyst
|
||||
name: Business Analyst
|
||||
file: .bmad-core/agents/analyst.md
|
||||
file: bmad-core/agents/analyst.md
|
||||
description: Requirements gathering and analysis
|
||||
- id: pm
|
||||
name: Product Manager
|
||||
file: .bmad-core/agents/pm.md
|
||||
file: bmad-core/agents/pm.md
|
||||
description: Product strategy and roadmap planning
|
||||
- id: architect
|
||||
name: Solution Architect
|
||||
file: .bmad-core/agents/architect.md
|
||||
file: bmad-core/agents/architect.md
|
||||
description: Technical design and architecture
|
||||
- id: po
|
||||
name: Product Owner
|
||||
file: .bmad-core/agents/po.md
|
||||
file: bmad-core/agents/po.md
|
||||
description: Backlog management and prioritization
|
||||
- id: sm
|
||||
name: Scrum Master
|
||||
file: .bmad-core/agents/sm.md
|
||||
file: bmad-core/agents/sm.md
|
||||
description: Agile process and story creation
|
||||
- id: dev
|
||||
name: Developer
|
||||
file: .bmad-core/agents/dev.md
|
||||
file: bmad-core/agents/dev.md
|
||||
description: Code implementation and testing
|
||||
- id: qa
|
||||
name: QA Engineer
|
||||
file: .bmad-core/agents/qa.md
|
||||
file: bmad-core/agents/qa.md
|
||||
description: Quality assurance and testing
|
||||
- id: ux-expert
|
||||
name: UX Expert
|
||||
file: .bmad-core/agents/ux-expert.md
|
||||
file: bmad-core/agents/ux-expert.md
|
||||
description: User experience design
|
||||
- id: bmad-master
|
||||
name: BMAD Master
|
||||
file: .bmad-core/agents/bmad-master.md
|
||||
file: bmad-core/agents/bmad-master.md
|
||||
description: BMAD framework expert and guide
|
||||
- id: bmad-orchestrator
|
||||
name: BMAD Orchestrator
|
||||
file: .bmad-core/agents/bmad-orchestrator.md
|
||||
file: bmad-core/agents/bmad-orchestrator.md
|
||||
description: Multi-agent workflow coordinator
|
||||
|
||||
@@ -30,6 +30,43 @@ class ConfigLoader {
|
||||
return config['available-agents'] || [];
|
||||
}
|
||||
|
||||
async getAvailableExpansionPacks() {
|
||||
const expansionPacksDir = path.join(this.getBmadCorePath(), '..', 'expansion-packs');
|
||||
|
||||
try {
|
||||
const entries = await fs.readdir(expansionPacksDir, { withFileTypes: true });
|
||||
const expansionPacks = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
const manifestPath = path.join(expansionPacksDir, entry.name, 'manifest.yml');
|
||||
|
||||
try {
|
||||
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
||||
const manifest = yaml.load(manifestContent);
|
||||
|
||||
expansionPacks.push({
|
||||
id: entry.name,
|
||||
name: manifest.name || entry.name,
|
||||
description: manifest.description || 'No description available',
|
||||
version: manifest.version || '1.0.0',
|
||||
author: manifest.author || 'Unknown',
|
||||
manifestPath: manifestPath,
|
||||
dependencies: manifest.dependencies || []
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(`Failed to read manifest for expansion pack ${entry.name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expansionPacks;
|
||||
} catch (error) {
|
||||
console.warn(`Failed to read expansion packs directory: ${error.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getAgentDependencies(agentId) {
|
||||
// Use DependencyResolver to dynamically parse agent dependencies
|
||||
const DependencyResolver = require('../../lib/dependency-resolver');
|
||||
@@ -77,8 +114,8 @@ class ConfigLoader {
|
||||
}
|
||||
|
||||
getBmadCorePath() {
|
||||
// Get the path to .bmad-core relative to the installer (now under tools)
|
||||
return path.join(__dirname, '..', '..', '..', '.bmad-core');
|
||||
// Get the path to bmad-core relative to the installer (now under tools)
|
||||
return path.join(__dirname, '..', '..', '..', 'bmad-core');
|
||||
}
|
||||
|
||||
getAgentPath(agentId) {
|
||||
|
||||
@@ -261,6 +261,10 @@ class Installer {
|
||||
}
|
||||
}
|
||||
|
||||
// Install expansion packs if requested
|
||||
const expansionFiles = await this.installExpansionPacks(installDir, config.expansionPacks, spinner);
|
||||
files.push(...expansionFiles);
|
||||
|
||||
// Set up IDE integration if requested
|
||||
const ides = config.ides || (config.ide ? [config.ide] : []);
|
||||
if (ides.length > 0) {
|
||||
@@ -505,6 +509,11 @@ class Installer {
|
||||
console.log(chalk.bold("\n🎯 Installation Summary:"));
|
||||
console.log(chalk.green("✓ .bmad-core framework installed with all agents and workflows"));
|
||||
|
||||
if (config.expansionPacks && config.expansionPacks.length > 0) {
|
||||
const packNames = config.expansionPacks.join(", ");
|
||||
console.log(chalk.green(`✓ Expansion packs installed: ${packNames}`));
|
||||
}
|
||||
|
||||
if (ides.length > 0) {
|
||||
const ideNames = ides.map(ide => {
|
||||
const ideConfig = configLoader.getIdeConfiguration(ide);
|
||||
@@ -569,6 +578,33 @@ class Installer {
|
||||
);
|
||||
}
|
||||
|
||||
async listExpansionPacks() {
|
||||
// Initialize ES modules
|
||||
await initializeModules();
|
||||
const expansionPacks = await this.getAvailableExpansionPacks();
|
||||
|
||||
console.log(chalk.bold("\nAvailable BMAD Expansion Packs:\n"));
|
||||
|
||||
if (expansionPacks.length === 0) {
|
||||
console.log(chalk.yellow("No expansion packs found."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (const pack of expansionPacks) {
|
||||
console.log(chalk.cyan(` ${pack.id.padEnd(20)}`),
|
||||
`${pack.name} v${pack.version}`);
|
||||
console.log(chalk.dim(` ${' '.repeat(22)}${pack.description}`));
|
||||
if (pack.author && pack.author !== 'Unknown') {
|
||||
console.log(chalk.dim(` ${' '.repeat(22)}by ${pack.author}`));
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.dim("Install with: npx bmad-method install --full --expansion-packs <id>\n")
|
||||
);
|
||||
}
|
||||
|
||||
async showStatus() {
|
||||
// Initialize ES modules
|
||||
await initializeModules();
|
||||
@@ -624,6 +660,96 @@ class Installer {
|
||||
return configLoader.getAvailableAgents();
|
||||
}
|
||||
|
||||
async getAvailableExpansionPacks() {
|
||||
return configLoader.getAvailableExpansionPacks();
|
||||
}
|
||||
|
||||
async installExpansionPacks(installDir, selectedPacks, spinner) {
|
||||
if (!selectedPacks || selectedPacks.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const installedFiles = [];
|
||||
const glob = require('glob');
|
||||
|
||||
for (const packId of selectedPacks) {
|
||||
spinner.text = `Installing expansion pack: ${packId}...`;
|
||||
|
||||
try {
|
||||
const expansionPacks = await this.getAvailableExpansionPacks();
|
||||
const pack = expansionPacks.find(p => p.id === packId);
|
||||
|
||||
if (!pack) {
|
||||
console.warn(`Expansion pack ${packId} not found, skipping...`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const expansionPackDir = path.dirname(pack.manifestPath);
|
||||
|
||||
// Define the folders to copy from expansion packs to .bmad-core
|
||||
const foldersToSync = [
|
||||
'agents',
|
||||
'agent-teams',
|
||||
'templates',
|
||||
'tasks',
|
||||
'checklists',
|
||||
'workflows',
|
||||
'data',
|
||||
'utils',
|
||||
'schemas'
|
||||
];
|
||||
|
||||
// Copy each folder if it exists
|
||||
for (const folder of foldersToSync) {
|
||||
const sourceFolder = path.join(expansionPackDir, folder);
|
||||
|
||||
// Check if folder exists in expansion pack
|
||||
if (await fileManager.pathExists(sourceFolder)) {
|
||||
// Get all files in this folder
|
||||
const files = glob.sync('**/*', {
|
||||
cwd: sourceFolder,
|
||||
nodir: true
|
||||
});
|
||||
|
||||
// Copy each file to the destination
|
||||
for (const file of files) {
|
||||
const sourcePath = path.join(sourceFolder, file);
|
||||
const destPath = path.join(installDir, '.bmad-core', folder, file);
|
||||
|
||||
if (await fileManager.copyFile(sourcePath, destPath)) {
|
||||
installedFiles.push(path.join('.bmad-core', folder, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also copy web-bundles if they exist (to a different location)
|
||||
const webBundlesSource = path.join(expansionPackDir, 'web-bundles');
|
||||
if (await fileManager.pathExists(webBundlesSource)) {
|
||||
const files = glob.sync('**/*', {
|
||||
cwd: webBundlesSource,
|
||||
nodir: true
|
||||
});
|
||||
|
||||
for (const file of files) {
|
||||
const sourcePath = path.join(webBundlesSource, file);
|
||||
const destPath = path.join(installDir, '.bmad-core', 'web-bundles', 'expansion-packs', packId, file);
|
||||
|
||||
if (await fileManager.copyFile(sourcePath, destPath)) {
|
||||
installedFiles.push(path.join('.bmad-core', 'web-bundles', 'expansion-packs', packId, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(chalk.green(`✓ Installed expansion pack: ${pack.name}`));
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`Failed to install expansion pack ${packId}: ${error.message}`));
|
||||
}
|
||||
}
|
||||
|
||||
return installedFiles;
|
||||
}
|
||||
|
||||
async findInstallation() {
|
||||
// Look for .bmad-core in current directory or parent directories
|
||||
let currentDir = process.cwd();
|
||||
|
||||
6
tools/installer/package-lock.json
generated
6
tools/installer/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bmad-method",
|
||||
"version": "4.0.1",
|
||||
"version": "4.3.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bmad-method",
|
||||
"version": "4.0.1",
|
||||
"version": "4.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^5.4.1",
|
||||
@@ -21,7 +21,7 @@
|
||||
"bmad-method": "bin/bmad.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/checkbox": {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"ora": "^8.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user