BMAD-METHOD/tools/cli/lib/cli-utils.js
Brian Madison 7eb52520fa Major Enhancements:
- Installation path is now fully configurable, allowing users to specify custom installation directories during setup
  - Default installation location changed to .bmad (hidden directory) for cleaner project root organization

    Web Bundle Improvements:

    - All web bundles (single agent and team) now include party mode support for multi-agent collaboration!
    - Advanced elicitation capabilities integrated into standalone agents
    - All bundles enhanced with party mode agent manifests
    - Added default-party.csv files to bmm, bmgd, and cis module teams
    - The default party file is what will be used with single agent bundles. teams can customize for different party configurations before web bundling through a setting in the team yaml file
    - New web bundle outputs for all agents (analyst, architect, dev, pm, sm, tea, tech-writer, ux-designer, game-*, creative-squad)

    Phase 4 Workflow Updates (In Progress):

    - Initiated shift to separate phase 4 implementation artifacts from documentation
        - Phase 4 implementation artifacts (stories, code review, sprint plan, context files) will move to dedicated location outside docs folder
        - Installer questions and configuration added for artifact path selection
        - Updated workflow.yaml files for code-review, sprint-planning, story-context, epic-tech-context, and retrospective workflows to support this, but still might require some udpates

    Additional Changes:

    - New agent and action command header models for standardization
    - Enhanced web-bundle-activation-steps fragment
    - Updated web-bundler.js to support new structure
    - VS Code settings updated for new .bmad directory
    - Party mode instructions and workflow enhanced for better orchestration

   IDE Installer Updates:

    - Show version number of installer in cli
    - improved Installer UX
    - Gemini TOML Improved to have clear loading instructions with @ commands
    - All tools agent launcher mds improved to use a central file template critical indication isntead of hardcoding in 2 different locations.
2025-11-09 17:39:05 -06:00

211 lines
6.2 KiB
JavaScript

const chalk = require('chalk');
const boxen = require('boxen');
const wrapAnsi = require('wrap-ansi');
const figlet = require('figlet');
const path = require('node:path');
const CLIUtils = {
/**
* Get version from package.json
*/
getVersion() {
try {
const packageJson = require(path.join(__dirname, '..', '..', '..', 'package.json'));
return packageJson.version || 'Unknown';
} catch {
return 'Unknown';
}
},
/**
* Display BMAD logo
* @param {boolean} clearScreen - Whether to clear the screen first (default: true for initial display only)
*/
displayLogo(clearScreen = true) {
if (clearScreen) {
console.clear();
}
const version = this.getVersion();
// ASCII art logo
const logo = `
██████╗ ███╗ ███╗ █████╗ ██████╗ ™
██╔══██╗████╗ ████║██╔══██╗██╔══██╗
██████╔╝██╔████╔██║███████║██║ ██║
██╔══██╗██║╚██╔╝██║██╔══██║██║ ██║
██████╔╝██║ ╚═╝ ██║██║ ██║██████╔╝
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝`;
console.log(chalk.cyan(logo));
console.log(chalk.dim(` Build More, Architect Dreams`) + chalk.cyan.bold(` v${version}`) + '\n');
},
/**
* Display section header
* @param {string} title - Section title
* @param {string} subtitle - Optional subtitle
*/
displaySection(title, subtitle = null) {
console.log('\n' + chalk.cyan('═'.repeat(80)));
console.log(chalk.cyan.bold(` ${title}`));
if (subtitle) {
console.log(chalk.dim(` ${subtitle}`));
}
console.log(chalk.cyan('═'.repeat(80)) + '\n');
},
/**
* Display info box
* @param {string|Array} content - Content to display
* @param {Object} options - Box options
*/
displayBox(content, options = {}) {
const defaultOptions = {
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan',
...options,
};
// Handle array content
let text = content;
if (Array.isArray(content)) {
text = content.join('\n\n');
}
// Wrap text to prevent overflow
const wrapped = wrapAnsi(text, 76, { hard: true, wordWrap: true });
console.log(boxen(wrapped, defaultOptions));
},
/**
* Display module configuration header
* @param {string} moduleName - Module name (fallback if no custom header)
* @param {string} header - Custom header from install-config.yaml
* @param {string} subheader - Custom subheader from install-config.yaml
*/
displayModuleConfigHeader(moduleName, header = null, subheader = null) {
// Simple blue banner with custom header/subheader if provided
console.log('\n' + chalk.cyan('─'.repeat(80)));
console.log(chalk.cyan(header || `Configuring ${moduleName.toUpperCase()} Module`));
if (subheader) {
console.log(chalk.dim(`${subheader}`));
}
console.log(chalk.cyan('─'.repeat(80)) + '\n');
},
/**
* Display module with no custom configuration
* @param {string} moduleName - Module name (fallback if no custom header)
* @param {string} header - Custom header from install-config.yaml
* @param {string} subheader - Custom subheader from install-config.yaml
*/
displayModuleNoConfig(moduleName, header = null, subheader = null) {
// Show full banner with header/subheader, just like modules with config
console.log('\n' + chalk.cyan('─'.repeat(80)));
console.log(chalk.cyan(header || `${moduleName.toUpperCase()} Module - No Custom Configuration`));
if (subheader) {
console.log(chalk.dim(`${subheader}`));
}
console.log(chalk.cyan('─'.repeat(80)) + '\n');
},
/**
* Display step indicator
* @param {number} current - Current step
* @param {number} total - Total steps
* @param {string} description - Step description
*/
displayStep(current, total, description) {
const progress = `[${current}/${total}]`;
console.log('\n' + chalk.cyan(progress) + ' ' + chalk.bold(description));
console.log(chalk.dim('─'.repeat(80 - progress.length - 1)) + '\n');
},
/**
* Display completion message
* @param {string} message - Completion message
*/
displayComplete(message) {
console.log(
'\n' +
boxen(chalk.green('✨ ' + message), {
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'green',
}),
);
},
/**
* Display error message
* @param {string} message - Error message
*/
displayError(message) {
console.log(
'\n' +
boxen(chalk.red('✗ ' + message), {
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'red',
}),
);
},
/**
* Format list for display
* @param {Array} items - Items to display
* @param {string} prefix - Item prefix
*/
formatList(items, prefix = '•') {
return items.map((item) => ` ${prefix} ${item}`).join('\n');
},
/**
* Clear previous lines
* @param {number} lines - Number of lines to clear
*/
clearLines(lines) {
for (let i = 0; i < lines; i++) {
process.stdout.moveCursor(0, -1);
process.stdout.clearLine(1);
}
},
/**
* Display table
* @param {Array} data - Table data
* @param {Object} options - Table options
*/
displayTable(data, options = {}) {
const Table = require('cli-table3');
const table = new Table({
style: {
head: ['cyan'],
border: ['dim'],
},
...options,
});
for (const row of data) table.push(row);
console.log(table.toString());
},
/**
* Display module completion message
* @param {string} moduleName - Name of the completed module
* @param {boolean} clearScreen - Whether to clear the screen first (deprecated, always false now)
*/
displayModuleComplete(moduleName, clearScreen = false) {
// No longer clear screen or show boxes - just a simple completion message
// This is deprecated but kept for backwards compatibility
},
};
module.exports = { CLIUtils };