mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-01-30 04:32:02 +00:00
157 lines
4.8 KiB
JavaScript
157 lines
4.8 KiB
JavaScript
const path = require('node:path');
|
|
const fs = require('fs-extra');
|
|
const chalk = require('chalk');
|
|
const { XmlHandler } = require('../lib/xml-handler');
|
|
|
|
class WebBundler {
|
|
constructor(options = {}) {
|
|
this.projectRoot = options.projectRoot || path.resolve(__dirname, '../../..');
|
|
this.modulesRoot = options.modulesRoot || path.join(this.projectRoot, 'src', 'modules');
|
|
this.outputRoot = options.outputRoot || path.join(this.projectRoot, 'web-bundles');
|
|
this.logger = options.logger || console;
|
|
this.xmlHandler = new XmlHandler();
|
|
}
|
|
|
|
async listModules() {
|
|
if (!(await fs.pathExists(this.modulesRoot))) {
|
|
return [];
|
|
}
|
|
|
|
const entries = await fs.readdir(this.modulesRoot, { withFileTypes: true });
|
|
return entries
|
|
.filter((entry) => entry.isDirectory())
|
|
.map((entry) => entry.name)
|
|
.sort();
|
|
}
|
|
|
|
async listAgents(moduleName) {
|
|
const agentsDir = path.join(this.modulesRoot, moduleName, 'agents');
|
|
if (!(await fs.pathExists(agentsDir))) {
|
|
return [];
|
|
}
|
|
|
|
const files = await this.findAgentFiles(agentsDir);
|
|
return files.map((file) => path.basename(file, '.agent.yaml')).sort();
|
|
}
|
|
|
|
async list() {
|
|
const modules = await this.listModules();
|
|
|
|
if (modules.length === 0) {
|
|
this.logger.log('No modules found.');
|
|
return;
|
|
}
|
|
|
|
this.logger.log(chalk.cyan('Available modules and agents:'));
|
|
for (const moduleName of modules) {
|
|
const agents = await this.listAgents(moduleName);
|
|
this.logger.log(` ${moduleName}: ${agents.length} agent(s)`);
|
|
for (const agent of agents) {
|
|
this.logger.log(` - ${agent}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
async clean() {
|
|
if (await fs.pathExists(this.outputRoot)) {
|
|
await fs.remove(this.outputRoot);
|
|
}
|
|
this.logger.log(chalk.green('OK: Cleaned web-bundles output'));
|
|
}
|
|
|
|
async bundleAll() {
|
|
const modules = await this.listModules();
|
|
if (modules.length === 0) {
|
|
this.logger.log('No modules found to bundle.');
|
|
return;
|
|
}
|
|
|
|
await fs.ensureDir(this.outputRoot);
|
|
for (const moduleName of modules) {
|
|
await this.bundleModule(moduleName);
|
|
}
|
|
}
|
|
|
|
async bundleModule(moduleName) {
|
|
const moduleRoot = path.join(this.modulesRoot, moduleName);
|
|
if (!(await fs.pathExists(moduleRoot))) {
|
|
throw new Error(`Module not found: ${moduleName}`);
|
|
}
|
|
|
|
const agentsDir = path.join(moduleRoot, 'agents');
|
|
if (!(await fs.pathExists(agentsDir))) {
|
|
this.logger.log(chalk.yellow(`Skipping ${moduleName}: no agents directory`));
|
|
return;
|
|
}
|
|
|
|
const outputModuleDir = path.join(this.outputRoot, moduleName, 'agents');
|
|
await fs.remove(outputModuleDir);
|
|
await fs.ensureDir(outputModuleDir);
|
|
|
|
const agentFiles = await this.findAgentFiles(agentsDir);
|
|
if (agentFiles.length === 0) {
|
|
this.logger.log(chalk.yellow(`Skipping ${moduleName}: no agent files found`));
|
|
return;
|
|
}
|
|
|
|
this.logger.log(chalk.cyan(`Bundling ${moduleName} (${agentFiles.length} agent(s))`));
|
|
for (const agentFile of agentFiles) {
|
|
await this.bundleAgentFile(moduleName, agentFile);
|
|
}
|
|
}
|
|
|
|
async bundleAgentByName(moduleName, agentName) {
|
|
const agentsDir = path.join(this.modulesRoot, moduleName, 'agents');
|
|
if (!(await fs.pathExists(agentsDir))) {
|
|
throw new Error(`Agents directory not found for module: ${moduleName}`);
|
|
}
|
|
|
|
const agentFiles = await this.findAgentFiles(agentsDir);
|
|
const match = agentFiles.find((file) => path.basename(file, '.agent.yaml') === agentName);
|
|
if (!match) {
|
|
throw new Error(`Agent not found: ${moduleName}/${agentName}`);
|
|
}
|
|
|
|
const outputModuleDir = path.join(this.outputRoot, moduleName, 'agents');
|
|
await fs.ensureDir(outputModuleDir);
|
|
await this.bundleAgentFile(moduleName, match);
|
|
}
|
|
|
|
async bundleAgentFile(moduleName, agentFile) {
|
|
const agentName = path.basename(agentFile, '.agent.yaml');
|
|
const outputFile = path.join(this.outputRoot, moduleName, 'agents', `${agentName}.xml`);
|
|
|
|
const bundled = await this.xmlHandler.buildFromYaml(agentFile, null, { forWebBundle: true });
|
|
const xml = this.extractXmlBlock(bundled);
|
|
|
|
await fs.writeFile(outputFile, xml, 'utf8');
|
|
this.logger.log(chalk.green(` OK: ${moduleName}/${agentName}`));
|
|
}
|
|
|
|
async findAgentFiles(rootDir) {
|
|
const entries = await fs.readdir(rootDir, { withFileTypes: true });
|
|
const files = [];
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(rootDir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
files.push(...(await this.findAgentFiles(fullPath)));
|
|
} else if (entry.isFile() && entry.name.endsWith('.agent.yaml')) {
|
|
files.push(fullPath);
|
|
}
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
extractXmlBlock(content) {
|
|
const match = content.match(/```xml\s*([\s\S]*?)```/);
|
|
if (!match) {
|
|
return content.trim() + '\n';
|
|
}
|
|
return match[1].trim() + '\n';
|
|
}
|
|
}
|
|
|
|
module.exports = { WebBundler };
|