mirror of
https://github.com/bmadcode/BMAD-METHOD.git
synced 2025-12-29 16:14:59 +00:00
installer updates working with basic flow
This commit is contained in:
@@ -2,6 +2,8 @@ const chalk = require('chalk');
|
||||
const path = require('node:path');
|
||||
const fs = require('node:fs');
|
||||
const readline = require('node:readline');
|
||||
const yaml = require('js-yaml');
|
||||
const inquirer = require('inquirer');
|
||||
const {
|
||||
findBmadConfig,
|
||||
resolvePath,
|
||||
@@ -18,6 +20,122 @@ const {
|
||||
updateManifestYaml,
|
||||
} = require('../lib/agent/installer');
|
||||
|
||||
/**
|
||||
* Initialize BMAD core infrastructure in a directory
|
||||
* @param {string} projectDir - Project directory where .bmad should be created
|
||||
* @param {string} bmadFolderName - Name of the BMAD folder (default: .bmad)
|
||||
* @returns {Promise<Object>} BMAD project info
|
||||
*/
|
||||
async function initializeBmadCore(projectDir, bmadFolderName = '.bmad') {
|
||||
const bmadDir = path.join(projectDir, bmadFolderName);
|
||||
const cfgDir = path.join(bmadDir, '_cfg');
|
||||
|
||||
console.log(chalk.cyan('\n🏗️ Initializing BMAD Core Infrastructure\n'));
|
||||
|
||||
// Use the ConfigCollector to ask proper core configuration questions
|
||||
const { ConfigCollector } = require('../installers/lib/core/config-collector');
|
||||
const configCollector = new ConfigCollector();
|
||||
|
||||
// Collect core configuration answers
|
||||
await configCollector.loadExistingConfig(projectDir);
|
||||
await configCollector.collectModuleConfig('core', projectDir, true, true);
|
||||
|
||||
// Extract core answers from allAnswers (they are prefixed with 'core_')
|
||||
const coreAnswers = {};
|
||||
if (configCollector.allAnswers) {
|
||||
for (const [key, value] of Object.entries(configCollector.allAnswers)) {
|
||||
if (key.startsWith('core_')) {
|
||||
const configKey = key.slice(5); // Remove 'core_' prefix
|
||||
coreAnswers[configKey] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ask for IDE selection
|
||||
console.log(chalk.cyan('\n💻 IDE Configuration\n'));
|
||||
console.log(chalk.dim('Select IDEs to integrate with the installed agents:'));
|
||||
|
||||
const { UI } = require('../lib/ui');
|
||||
const ui = new UI();
|
||||
const ideConfig = await ui.promptToolSelection(projectDir, ['core']);
|
||||
const selectedIdes = ideConfig.ides || [];
|
||||
|
||||
// Create directory structure
|
||||
console.log(chalk.dim('\nCreating directory structure...'));
|
||||
await fs.promises.mkdir(bmadDir, { recursive: true });
|
||||
await fs.promises.mkdir(cfgDir, { recursive: true });
|
||||
await fs.promises.mkdir(path.join(bmadDir, 'core'), { recursive: true });
|
||||
await fs.promises.mkdir(path.join(bmadDir, 'custom', 'agents'), { recursive: true });
|
||||
await fs.promises.mkdir(path.join(cfgDir, 'agents'), { recursive: true });
|
||||
await fs.promises.mkdir(path.join(cfgDir, 'custom', 'agents'), { recursive: true });
|
||||
|
||||
// Create core config.yaml file
|
||||
const coreConfigFile = {
|
||||
'# CORE Module Configuration': 'Generated by BMAD Agent Installer',
|
||||
Version: require(path.join(__dirname, '../../../package.json')).version,
|
||||
Date: new Date().toISOString(),
|
||||
bmad_folder: bmadFolderName,
|
||||
...coreAnswers,
|
||||
};
|
||||
|
||||
const coreConfigPath = path.join(bmadDir, 'core', 'config.yaml');
|
||||
await fs.promises.writeFile(coreConfigPath, yaml.dump(coreConfigFile), 'utf8');
|
||||
|
||||
// Create manifest.yaml with complete structure
|
||||
const manifest = {
|
||||
version: require(path.join(__dirname, '../../../package.json')).version,
|
||||
date: new Date().toISOString(),
|
||||
user_name: coreAnswers.user_name,
|
||||
communication_language: coreAnswers.communication_language,
|
||||
document_output_language: coreAnswers.document_output_language,
|
||||
output_folder: coreAnswers.output_folder,
|
||||
install_user_docs: coreAnswers.install_user_docs,
|
||||
bmad_folder: bmadFolderName,
|
||||
modules: ['core'],
|
||||
ides: selectedIdes,
|
||||
custom_agents: [],
|
||||
};
|
||||
|
||||
const manifestPath = path.join(cfgDir, 'manifest.yaml');
|
||||
await fs.promises.writeFile(manifestPath, yaml.dump(manifest), 'utf8');
|
||||
|
||||
// Create empty manifests
|
||||
const agentManifestPath = path.join(cfgDir, 'agent-manifest.csv');
|
||||
await fs.promises.writeFile(agentManifestPath, 'type,subtype,name,path,display_name,description,author,version,tags\n', 'utf8');
|
||||
|
||||
// Setup IDE configurations
|
||||
if (selectedIdes.length > 0) {
|
||||
console.log(chalk.dim('\nSetting up IDE configurations...'));
|
||||
const { IdeManager } = require('../installers/lib/ide/manager');
|
||||
const ideManager = new IdeManager();
|
||||
|
||||
for (const ide of selectedIdes) {
|
||||
await ideManager.setup(ide, projectDir, bmadDir, {
|
||||
selectedModules: ['core'],
|
||||
skipModuleInstall: false,
|
||||
verbose: false,
|
||||
preCollectedConfig: coreAnswers,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(chalk.green('\n✓ BMAD core infrastructure initialized'));
|
||||
console.log(chalk.dim(` BMAD folder: ${bmadDir}`));
|
||||
console.log(chalk.dim(` Core config: ${coreConfigPath}`));
|
||||
console.log(chalk.dim(` Manifest: ${manifestPath}`));
|
||||
if (selectedIdes.length > 0) {
|
||||
console.log(chalk.dim(` IDEs configured: ${selectedIdes.join(', ')}`));
|
||||
}
|
||||
|
||||
return {
|
||||
projectRoot: projectDir,
|
||||
bmadFolder: bmadDir,
|
||||
cfgFolder: cfgDir,
|
||||
manifestFile: agentManifestPath,
|
||||
ides: selectedIdes,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
command: 'agent-install',
|
||||
description: 'Install and compile BMAD agents with personalization',
|
||||
@@ -196,12 +314,55 @@ module.exports = {
|
||||
|
||||
// If no target specified, prompt for it
|
||||
if (targetDir) {
|
||||
// If target provided via --destination, check if it's a project root and adjust
|
||||
// Check if target has BMAD infrastructure
|
||||
const otherProject = detectBmadProject(targetDir);
|
||||
if (otherProject && !targetDir.includes('agents')) {
|
||||
// User specified project root, redirect to custom agents folder
|
||||
targetDir = path.join(otherProject.bmadFolder, 'custom', 'agents');
|
||||
console.log(chalk.dim(` Auto-selecting custom agents folder: ${targetDir}`));
|
||||
|
||||
if (!otherProject) {
|
||||
// No BMAD infrastructure found - offer to initialize
|
||||
console.log(chalk.yellow(`\n⚠️ No BMAD infrastructure found in: ${targetDir}`));
|
||||
|
||||
const initResponse = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'initialize',
|
||||
message: 'Initialize BMAD core infrastructure here? (Choose No for direct installation)',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (initResponse.initialize) {
|
||||
// Initialize BMAD core
|
||||
targetDir = path.resolve(targetDir);
|
||||
await initializeBmadCore(targetDir, '.bmad');
|
||||
// Set targetDir to the custom agents folder
|
||||
targetDir = path.join(targetDir, '.bmad', 'custom', 'agents');
|
||||
console.log(chalk.dim(` Agent will be installed to: ${targetDir}`));
|
||||
} else {
|
||||
// User declined - keep original targetDir
|
||||
console.log(chalk.yellow(` Installing agent directly to: ${targetDir}`));
|
||||
}
|
||||
} else if (otherProject && !targetDir.includes('agents')) {
|
||||
console.log(chalk.yellow(`\n⚠️ Path is inside BMAD project: ${otherProject.projectRoot}`));
|
||||
|
||||
const projectChoice = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'choice',
|
||||
message: 'Choose installation method:',
|
||||
choices: [
|
||||
{ name: `Install to BMAD's custom agents folder (${otherProject.bmadFolder}/custom/agents)`, value: 'bmad' },
|
||||
{ name: `Install directly to specified path (${targetDir})`, value: 'direct' },
|
||||
],
|
||||
default: 'bmad',
|
||||
},
|
||||
]);
|
||||
|
||||
if (projectChoice.choice === 'bmad') {
|
||||
targetDir = path.join(otherProject.bmadFolder, 'custom', 'agents');
|
||||
console.log(chalk.dim(` Installing to BMAD custom agents folder: ${targetDir}`));
|
||||
} else {
|
||||
console.log(chalk.yellow(` Installing directly to: ${targetDir}`));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const rl = readline.createInterface({
|
||||
@@ -214,38 +375,72 @@ module.exports = {
|
||||
// Option 1: Current project's custom agents folder
|
||||
const currentCustom = path.join(config.bmadFolder, 'custom', 'agents');
|
||||
console.log(` 1. Current project: ${chalk.dim(currentCustom)}`);
|
||||
|
||||
// Option 2: Specify another project path
|
||||
console.log(` 2. Another project (enter path)`);
|
||||
console.log(` 2. Enter path directly (e.g., /Users/brianmadison/dev/test)`);
|
||||
|
||||
const choice = await new Promise((resolve) => {
|
||||
rl.question('\n Select option (1 or path): ', resolve);
|
||||
rl.question('\n Select option (1 or 2): ', resolve);
|
||||
});
|
||||
|
||||
if (choice.trim() === '1' || choice.trim() === '') {
|
||||
targetDir = currentCustom;
|
||||
} else if (choice.trim() === '2') {
|
||||
const projectPath = await new Promise((resolve) => {
|
||||
rl.question(' Project path: ', resolve);
|
||||
const userPath = await new Promise((resolve) => {
|
||||
rl.question(' Enter path: ', resolve);
|
||||
});
|
||||
|
||||
// Detect if it's a BMAD project and use its custom folder
|
||||
const otherProject = detectBmadProject(path.resolve(projectPath));
|
||||
const otherProject = detectBmadProject(path.resolve(userPath));
|
||||
|
||||
if (otherProject) {
|
||||
targetDir = path.join(otherProject.bmadFolder, 'custom', 'agents');
|
||||
console.log(chalk.dim(` Found BMAD project, using: ${targetDir}`));
|
||||
console.log(chalk.yellow(`\n⚠️ Path is inside BMAD project: ${otherProject.projectRoot}`));
|
||||
|
||||
const projectChoice = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'choice',
|
||||
message: 'Choose installation method:',
|
||||
choices: [
|
||||
{ name: `Install to BMAD's custom agents folder (${otherProject.bmadFolder}/custom/agents)`, value: 'bmad' },
|
||||
{ name: `Install directly to specified path (${userPath})`, value: 'direct' },
|
||||
],
|
||||
default: 'bmad',
|
||||
},
|
||||
]);
|
||||
|
||||
if (projectChoice.choice === 'bmad') {
|
||||
targetDir = path.join(otherProject.bmadFolder, 'custom', 'agents');
|
||||
console.log(chalk.dim(` Installing to BMAD custom agents folder: ${targetDir}`));
|
||||
} else {
|
||||
targetDir = path.resolve(userPath);
|
||||
console.log(chalk.yellow(` Installing directly to: ${targetDir}`));
|
||||
}
|
||||
} else {
|
||||
targetDir = path.resolve(projectPath);
|
||||
// No BMAD found - offer to initialize
|
||||
console.log(chalk.yellow(`\n⚠️ No BMAD infrastructure found in: ${userPath}`));
|
||||
|
||||
const initResponse = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'initialize',
|
||||
message: 'Initialize BMAD core infrastructure here? (Choose No for direct installation)',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (initResponse.initialize) {
|
||||
await initializeBmadCore(path.resolve(userPath), '.bmad');
|
||||
targetDir = path.join(path.resolve(userPath), '.bmad', 'custom', 'agents');
|
||||
console.log(chalk.dim(` Agent will be installed to: ${targetDir}`));
|
||||
} else {
|
||||
// User declined - create the directory and install directly
|
||||
targetDir = path.resolve(userPath);
|
||||
console.log(chalk.yellow(` Installing agent directly to: ${targetDir}`));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// User entered a path directly
|
||||
const otherProject = detectBmadProject(path.resolve(choice));
|
||||
if (otherProject) {
|
||||
targetDir = path.join(otherProject.bmadFolder, 'custom', 'agents');
|
||||
console.log(chalk.dim(` Found BMAD project, using: ${targetDir}`));
|
||||
} else {
|
||||
targetDir = path.resolve(choice);
|
||||
}
|
||||
console.log(chalk.red(' Invalid selection. Please choose 1 or 2.'));
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
rl.close();
|
||||
|
||||
Reference in New Issue
Block a user