installation intro and outtro custom messages, configurable in install-messages.yaml

This commit is contained in:
Brian Madison 2025-12-23 21:43:29 +08:00
parent c0f5d33c61
commit 4195eb3b30
7 changed files with 153 additions and 98 deletions

View File

@ -92,6 +92,3 @@ jobs:
- name: Test agent compilation components
run: npm run test:install
- name: Validate web bundles
run: npm run validate:bundles

View File

@ -39,11 +39,10 @@
"release:minor": "gh workflow run \"Manual Release\" -f version_bump=minor",
"release:patch": "gh workflow run \"Manual Release\" -f version_bump=patch",
"release:watch": "gh run watch",
"test": "npm run test:schemas && npm run test:install && npm run validate:bundles && npm run validate:schemas && npm run lint && npm run lint:md && npm run format:check",
"test": "npm run test:schemas && npm run test:install && npm run validate:schemas && npm run lint && npm run lint:md && npm run format:check",
"test:coverage": "c8 --reporter=text --reporter=html npm run test:schemas",
"test:install": "node test/test-installation-components.js",
"test:schemas": "node test/test-agent-schema.js",
"validate:bundles": "node tools/validate-bundles.js",
"validate:schemas": "node tools/validate-agent-schema.js"
},
"lint-staged": {

View File

@ -26,11 +26,12 @@ module.exports = {
const result = await installer.quickUpdate(config);
console.log(chalk.green('\n✨ Quick update complete!'));
console.log(chalk.cyan(`Updated ${result.moduleCount} modules with preserved settings`));
console.log(
chalk.magenta(
"\n📋 Want to see what's new? Check out the changelog: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md",
),
);
// Display version-specific end message
const { MessageLoader } = require('../installers/lib/message-loader');
const messageLoader = new MessageLoader();
messageLoader.displayEndMessage();
process.exit(0);
return;
}
@ -97,6 +98,11 @@ module.exports = {
}
}
// Display version-specific end message from install-messages.yaml
const { MessageLoader } = require('../installers/lib/message-loader');
const messageLoader = new MessageLoader();
messageLoader.displayEndMessage();
process.exit(0);
}
} catch (error) {

View File

@ -0,0 +1,52 @@
# BMAD Installer Messages
# These messages are displayed during installation
# Edit this file to change what users see during the install process
# Display at the START of installation (after logo, before prompts)
startMessage: |
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎉🎉 Happy Holidays and New Year 🍾🍾
IMPORTANT Changes with Version Alpha.20 - PLEASE READ THIS if upgrading from earlier Alpha Versions:
1. The BMad Core default output folder has changed from docs to `_bmad-output`. `docs` is meant for long-term artifacts, which you can always decide to move content to.
2. If utilizing the BMad Method Module (BMM) please be aware of the following important recent changes:
- Phases 1-3 (Analysis, Planning, Solutioning) will now default output to _bmad-output/planning-artifacts
- Phase 4 (Implementation) will now default output to _bmad-output/implementation-artifacts
- Long term project knowledge (research, docs, references, document-project output) will now default to docs/
IT IS STRONGLY SUGGESTED to align with these folder conventions instead of dumping all to docs/ - if you are upgrading from a prior
version where all output was going to docs or docs/sprint-artifacts, it is suggested to reset configs to these new values.
If you have anything in progress, you can move what was in sprint-artifacts to _bmad-output/implementation-artifacts, and if you had brainstorming
content, a PRD, UX or Architecture, you can move the content to _bmad-output/planning-artifacts.
Read the latest updates before continuing:
https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Display at the END of installation (after all setup completes)
endMessage: |
════════════════════════════════════════════════════════════════════════════════
✨ BMAD IS READY TO USE!
ONE FINAL NOTE WITH VERSION Alpha.20: Phase 4 (Implementation) is still in the process of being migrated to the improved workflow progressive disclosure system.
Along with this, the full conversion to the new path locations for content being searched may possibly be incomplete. If you run a workflow that relies on finding input documents automatically, and you notice they are not being found / looking in the wrong location, either:
1. Manually specify the correct input location when prompted
2. Open an issue on GitHub so we can address the problem quickly if you think its a bug.
3. Ensure your content is in the new locations for best results:
- Planning Artifacts (Phases 1-3): _bmad-output/planning-artifacts
- Implementation Artifacts (Phase 4): _bmad-output/implementation-artifacts
- Long Term Project Knowledge (docs, research, references): docs/
Thank you for helping test the early release version of the new BMad Core and BMad Method!
Stable Beta coming soon - please read the full README.md and linked documentation to get started.
And again, here is the Change Log with all the details of recent updates: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md
════════════════════════════════════════════════════════════════════════════════

View File

@ -0,0 +1,85 @@
const fs = require('fs-extra');
const path = require('node:path');
const yaml = require('yaml');
const chalk = require('chalk');
/**
* Load and display installer messages from messages.yaml
*/
class MessageLoader {
constructor() {}
/**
* Load messages from the YAML file
* @returns {Object|null} Messages object or null if not found
*/
load() {
if (this.messages) {
return this.messages;
}
const messagesPath = path.join(__dirname, '..', 'install-messages.yaml');
try {
const content = fs.readFileSync(messagesPath, 'utf8');
this.messages = yaml.parse(content);
return this.messages;
} catch {
// File doesn't exist or is invalid - return null
return null;
}
}
/**
* Get the start message for display
* @returns {string|null} Start message or null
*/
getStartMessage() {
const messages = this.load();
return messages?.startMessage || null;
}
/**
* Get the end message for display
* @returns {string|null} End message or null
*/
getEndMessage() {
const messages = this.load();
return messages?.endMessage || null;
}
/**
* Display the start message (after logo, before prompts)
*/
displayStartMessage() {
const message = this.getStartMessage();
if (message) {
console.log(chalk.cyan(message));
console.log();
}
}
/**
* Display the end message (after installation completes)
*/
displayEndMessage() {
const message = this.getEndMessage();
if (message) {
console.log();
console.log(chalk.cyan(message));
}
}
/**
* Check if messages exist for the current version
* @param {string} currentVersion - Current package version
* @returns {boolean} True if messages match current version
*/
isCurrent(currentVersion) {
const messages = this.load();
return messages && messages.version === currentVersion;
}
messages = null;
}
module.exports = { MessageLoader };

View File

@ -17,7 +17,10 @@ class UI {
async promptInstall() {
CLIUtils.displayLogo();
console.log(chalk.cyan('\nRead the latest updates: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md\n'));
// Display version-specific start message from install-messages.yaml
const { MessageLoader } = require('../installers/lib/message-loader');
const messageLoader = new MessageLoader();
messageLoader.displayStartMessage();
const confirmedDirectory = await this.getConfirmedDirectory();

View File

@ -1,87 +0,0 @@
const fs = require('fs-extra');
const path = require('node:path');
const xml2js = require('xml2js');
const chalk = require('chalk');
const glob = require('glob');
async function validateXmlFile(filePath) {
try {
const content = await fs.readFile(filePath, 'utf8');
await xml2js.parseStringPromise(content, {
strict: true,
explicitArray: false,
});
return { valid: true };
} catch (error) {
return { valid: false, error: error.message };
}
}
async function validateAllBundles() {
console.log(chalk.cyan.bold('\n═══════════════════════════════════════════════'));
console.log(chalk.cyan.bold(' VALIDATING WEB BUNDLE XML FILES'));
console.log(chalk.cyan.bold('═══════════════════════════════════════════════\n'));
const bundlesDir = path.join(__dirname, '..', 'web-bundles');
// Find all XML files in web-bundles
const pattern = path.join(bundlesDir, '**/*.xml');
const files = glob.sync(pattern);
if (files.length === 0) {
console.log(chalk.yellow('No XML files found in web-bundles directory'));
return;
}
console.log(`Found ${chalk.bold(files.length)} XML files to validate\n`);
let validCount = 0;
let invalidCount = 0;
const invalidFiles = [];
for (const file of files) {
const relativePath = path.relative(bundlesDir, file);
const result = await validateXmlFile(file);
if (result.valid) {
console.log(`${chalk.green('✓')} ${relativePath}`);
validCount++;
} else {
console.log(`${chalk.red('✗')} ${relativePath}`);
console.log(` ${chalk.red('→')} ${result.error}`);
invalidCount++;
invalidFiles.push({ path: relativePath, error: result.error });
}
}
// Summary
console.log(chalk.cyan.bold('\n═══════════════════════════════════════════════'));
console.log(chalk.cyan.bold(' SUMMARY'));
console.log(chalk.cyan.bold('═══════════════════════════════════════════════\n'));
console.log(` Total files checked: ${chalk.bold(files.length)}`);
console.log(` Valid XML files: ${chalk.green(validCount)}`);
console.log(` Invalid XML files: ${invalidCount > 0 ? chalk.red(invalidCount) : chalk.green(invalidCount)}`);
if (invalidFiles.length > 0) {
console.log(chalk.red.bold('\n Invalid Files:'));
for (const { path, error } of invalidFiles) {
console.log(` ${chalk.red('•')} ${path}`);
if (error.length > 100) {
console.log(` ${error.slice(0, 100)}...`);
} else {
console.log(` ${error}`);
}
}
}
console.log(chalk.cyan.bold('\n═══════════════════════════════════════════════\n'));
process.exit(invalidCount > 0 ? 1 : 0);
}
// Run validation
validateAllBundles().catch((error) => {
console.error(chalk.red('Error running validation:'), error);
process.exit(1);
});