mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-01-30 04:32:02 +00:00
Project Cleanup of Agents Menus, BMB module removal to other repo
This commit is contained in:
@@ -82,11 +82,12 @@ class DependencyResolver {
|
||||
// Check if this is a source directory (has 'src' subdirectory)
|
||||
const srcDir = path.join(bmadDir, 'src');
|
||||
if (await fs.pathExists(srcDir)) {
|
||||
// Source directory structure: src/core or src/modules/xxx
|
||||
moduleDir = module === 'core' ? path.join(srcDir, 'core') : path.join(srcDir, 'modules', module);
|
||||
} else {
|
||||
// Installed directory structure: bmad/core or bmad/modules/xxx
|
||||
moduleDir = module === 'core' ? path.join(bmadDir, 'core') : path.join(bmadDir, 'modules', module);
|
||||
// Source directory structure: src/core or src/bmm
|
||||
if (module === 'core') {
|
||||
moduleDir = path.join(srcDir, 'core');
|
||||
} else if (module === 'bmm') {
|
||||
moduleDir = path.join(srcDir, 'bmm');
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await fs.pathExists(moduleDir))) {
|
||||
@@ -397,7 +398,8 @@ class DependencyResolver {
|
||||
|
||||
// Try to resolve as if it's in src structure
|
||||
// bmad/core/tasks/foo.md -> src/core/tasks/foo.md
|
||||
// bmad/bmm/tasks/bar.md -> src/modules/bmm/tasks/bar.md
|
||||
// bmad/bmm/tasks/bar.md -> src/bmm/tasks/bar.md (bmm is directly under src/)
|
||||
// bmad/cis/agents/bar.md -> src/modules/cis/agents/bar.md
|
||||
|
||||
if (bmadPath.startsWith('core/')) {
|
||||
const corePath = path.join(bmadDir, bmadPath);
|
||||
@@ -411,7 +413,14 @@ class DependencyResolver {
|
||||
const parts = bmadPath.split('/');
|
||||
const module = parts[0];
|
||||
const rest = parts.slice(1).join('/');
|
||||
const modulePath = path.join(bmadDir, 'modules', module, rest);
|
||||
let modulePath;
|
||||
if (module === 'bmm') {
|
||||
// bmm is directly under src/
|
||||
modulePath = path.join(bmadDir, module, rest);
|
||||
} else {
|
||||
// Other modules are under modules/
|
||||
modulePath = path.join(bmadDir, 'modules', module, rest);
|
||||
}
|
||||
|
||||
if (await fs.pathExists(modulePath)) {
|
||||
paths.push(modulePath);
|
||||
@@ -571,10 +580,12 @@ class DependencyResolver {
|
||||
const relative = path.relative(bmadDir, filePath);
|
||||
const parts = relative.split(path.sep);
|
||||
|
||||
// Handle source directory structure (src/core or src/modules/xxx)
|
||||
// Handle source directory structure (src/core, src/bmm, or src/modules/xxx)
|
||||
if (parts[0] === 'src') {
|
||||
if (parts[1] === 'core') {
|
||||
return 'core';
|
||||
} else if (parts[1] === 'bmm') {
|
||||
return 'bmm';
|
||||
} else if (parts[1] === 'modules' && parts.length > 2) {
|
||||
return parts[2];
|
||||
}
|
||||
@@ -616,27 +627,24 @@ class DependencyResolver {
|
||||
let moduleBase;
|
||||
|
||||
// Check if file is in source directory structure
|
||||
if (file.includes('/src/core/') || file.includes('/src/modules/')) {
|
||||
moduleBase = module === 'core' ? path.join(bmadDir, 'src', 'core') : path.join(bmadDir, 'src', 'modules', module);
|
||||
if (file.includes('/src/core/') || file.includes('/src/bmm/')) {
|
||||
if (module === 'core') {
|
||||
moduleBase = path.join(bmadDir, 'src', 'core');
|
||||
} else if (module === 'bmm') {
|
||||
moduleBase = path.join(bmadDir, 'src', 'bmm');
|
||||
}
|
||||
} else {
|
||||
// Installed structure
|
||||
moduleBase = module === 'core' ? path.join(bmadDir, 'core') : path.join(bmadDir, 'modules', module);
|
||||
}
|
||||
|
||||
const relative = path.relative(moduleBase, file);
|
||||
|
||||
// Check file path for categorization
|
||||
// Brain-tech files are data, not tasks (even though they're in tasks/brain-tech/)
|
||||
if (file.includes('/brain-tech/')) {
|
||||
organized[module].data.push(file);
|
||||
} else if (relative.startsWith('agents/') || file.includes('/agents/')) {
|
||||
if (relative.startsWith('agents/') || file.includes('/agents/')) {
|
||||
organized[module].agents.push(file);
|
||||
} else if (relative.startsWith('tasks/') || file.includes('/tasks/')) {
|
||||
organized[module].tasks.push(file);
|
||||
} else if (relative.startsWith('tools/') || file.includes('/tools/')) {
|
||||
organized[module].tools.push(file);
|
||||
} else if (relative.includes('template') || file.includes('/templates/')) {
|
||||
organized[module].templates.push(file);
|
||||
} else if (relative.includes('data/')) {
|
||||
organized[module].data.push(file);
|
||||
} else {
|
||||
|
||||
@@ -167,11 +167,10 @@ class KiroCliSetup extends BaseIdeSetup {
|
||||
const srcIndex = pathParts.indexOf('src');
|
||||
if (srcIndex + 3 < pathParts.length) {
|
||||
const folderAfterSrc = pathParts[srcIndex + 1];
|
||||
// Handle both src/core/agents and src/modules/[module]/agents patterns
|
||||
if (folderAfterSrc === 'core') {
|
||||
moduleName = 'core';
|
||||
} else if (folderAfterSrc === 'modules') {
|
||||
moduleName = pathParts[srcIndex + 2]; // The actual module name
|
||||
} else if (folderAfterSrc === 'bmm') {
|
||||
moduleName = 'bmm';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,15 +108,16 @@ class WorkflowCommandGenerator {
|
||||
const template = await fs.readFile(templatePath, 'utf8');
|
||||
|
||||
// Convert source path to installed path
|
||||
// From: /Users/.../src/modules/bmm/workflows/.../workflow.yaml
|
||||
// From: /Users/.../src/bmm/workflows/.../workflow.yaml
|
||||
// To: {project-root}/_bmad/bmm/workflows/.../workflow.yaml
|
||||
let workflowPath = workflow.path;
|
||||
|
||||
// Extract the relative path from source
|
||||
if (workflowPath.includes('/src/modules/')) {
|
||||
const match = workflowPath.match(/\/src\/modules\/(.+)/);
|
||||
if (workflowPath.includes('/src/bmm/')) {
|
||||
// bmm is directly under src/
|
||||
const match = workflowPath.match(/\/src\/bmm\/(.+)/);
|
||||
if (match) {
|
||||
workflowPath = `${this.bmadFolderName}/${match[1]}`;
|
||||
workflowPath = `${this.bmadFolderName}/bmm/${match[1]}`;
|
||||
}
|
||||
} else if (workflowPath.includes('/src/core/')) {
|
||||
const match = workflowPath.match(/\/src\/core\/(.+)/);
|
||||
@@ -208,19 +209,19 @@ When running any workflow:
|
||||
transformWorkflowPath(workflowPath) {
|
||||
let transformed = workflowPath;
|
||||
|
||||
if (workflowPath.includes('/src/modules/')) {
|
||||
const match = workflowPath.match(/\/src\/modules\/(.+)/);
|
||||
if (workflowPath.includes('/src/bmm/')) {
|
||||
const match = workflowPath.match(/\/src\/bmm\/(.+)/);
|
||||
if (match) {
|
||||
transformed = `{project-root}/${this.bmadFolderName}/${match[1]}`;
|
||||
transformed = `{project-root}/${this.bmadFolderName}/bmm/${match[1]}`;
|
||||
} else if (workflowPath.includes('/src/core/')) {
|
||||
const match = workflowPath.match(/\/src\/core\/(.+)/);
|
||||
if (match) {
|
||||
transformed = `{project-root}/${this.bmadFolderName}/core/${match[1]}`;
|
||||
}
|
||||
}
|
||||
} else if (workflowPath.includes('/src/core/')) {
|
||||
const match = workflowPath.match(/\/src\/core\/(.+)/);
|
||||
if (match) {
|
||||
transformed = `{project-root}/${this.bmadFolderName}/core/${match[1]}`;
|
||||
}
|
||||
}
|
||||
|
||||
return transformed;
|
||||
return transformed;
|
||||
}
|
||||
}
|
||||
|
||||
async loadWorkflowManifest(bmadDir) {
|
||||
|
||||
@@ -26,8 +26,6 @@ const { ExternalModuleManager } = require('./external-manager');
|
||||
*/
|
||||
class ModuleManager {
|
||||
constructor(options = {}) {
|
||||
// Path to source modules directory
|
||||
this.modulesSourcePath = getSourcePath('modules');
|
||||
this.xmlHandler = new XmlHandler();
|
||||
this.bmadFolderName = 'bmad'; // Default, can be overridden
|
||||
this.customModulePaths = new Map(); // Initialize custom module paths
|
||||
@@ -189,43 +187,20 @@ class ModuleManager {
|
||||
|
||||
/**
|
||||
* List all available modules (excluding core which is always installed)
|
||||
* bmm is the only built-in module, directly under src/bmm
|
||||
* All other modules come from external-official-modules.yaml
|
||||
* @returns {Object} Object with modules array and customModules array
|
||||
*/
|
||||
async listAvailable() {
|
||||
const modules = [];
|
||||
const customModules = [];
|
||||
|
||||
// First, scan src/modules (the standard location)
|
||||
if (await fs.pathExists(this.modulesSourcePath)) {
|
||||
const entries = await fs.readdir(this.modulesSourcePath, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
const modulePath = path.join(this.modulesSourcePath, entry.name);
|
||||
// Check for module structure (module.yaml OR custom.yaml)
|
||||
const moduleConfigPath = path.join(modulePath, 'module.yaml');
|
||||
const installerConfigPath = path.join(modulePath, '_module-installer', 'module.yaml');
|
||||
const customConfigPath = path.join(modulePath, '_module-installer', 'custom.yaml');
|
||||
|
||||
// Skip if this doesn't look like a module
|
||||
if (
|
||||
!(await fs.pathExists(moduleConfigPath)) &&
|
||||
!(await fs.pathExists(installerConfigPath)) &&
|
||||
!(await fs.pathExists(customConfigPath))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip core module - it's always installed first and not selectable
|
||||
if (entry.name === 'core') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const moduleInfo = await this.getModuleInfo(modulePath, entry.name, 'src/modules');
|
||||
if (moduleInfo) {
|
||||
modules.push(moduleInfo);
|
||||
}
|
||||
}
|
||||
// Add built-in bmm module (directly under src/bmm)
|
||||
const bmmPath = getSourcePath('bmm');
|
||||
if (await fs.pathExists(bmmPath)) {
|
||||
const bmmInfo = await this.getModuleInfo(bmmPath, 'bmm', 'src/bmm');
|
||||
if (bmmInfo) {
|
||||
modules.push(bmmInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +256,8 @@ class ModuleManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Mark as custom if it's using custom.yaml OR if it's outside src/modules
|
||||
const isCustomSource = sourceDescription !== 'src/modules';
|
||||
// Mark as custom if it's using custom.yaml OR if it's outside src/bmm or src/core
|
||||
const isCustomSource = sourceDescription !== 'src/bmm' && sourceDescription !== 'src/core' && sourceDescription !== 'src/modules';
|
||||
const moduleInfo = {
|
||||
id: defaultName,
|
||||
path: modulePath,
|
||||
@@ -331,40 +306,11 @@ class ModuleManager {
|
||||
return this.customModulePaths.get(moduleCode);
|
||||
}
|
||||
|
||||
// Search in src/modules by READING module.yaml files to match by code
|
||||
if (await fs.pathExists(this.modulesSourcePath)) {
|
||||
const entries = await fs.readdir(this.modulesSourcePath, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
const modulePath = path.join(this.modulesSourcePath, entry.name);
|
||||
|
||||
// Read module.yaml to get the code
|
||||
const moduleConfigPath = path.join(modulePath, 'module.yaml');
|
||||
const installerConfigPath = path.join(modulePath, '_module-installer', 'module.yaml');
|
||||
const customConfigPath = path.join(modulePath, '_module-installer', 'custom.yaml');
|
||||
|
||||
let configPath = null;
|
||||
if (await fs.pathExists(moduleConfigPath)) {
|
||||
configPath = moduleConfigPath;
|
||||
} else if (await fs.pathExists(installerConfigPath)) {
|
||||
configPath = installerConfigPath;
|
||||
} else if (await fs.pathExists(customConfigPath)) {
|
||||
configPath = customConfigPath;
|
||||
}
|
||||
|
||||
if (configPath) {
|
||||
try {
|
||||
const configContent = await fs.readFile(configPath, 'utf8');
|
||||
const config = yaml.parse(configContent);
|
||||
if (config.code === moduleCode) {
|
||||
return modulePath;
|
||||
}
|
||||
} catch (error) {
|
||||
// Continue to next module if parse fails
|
||||
console.warn(`Warning: Failed to parse module config at ${configPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for built-in bmm module (directly under src/bmm)
|
||||
if (moduleCode === 'bmm') {
|
||||
const bmmPath = getSourcePath('bmm');
|
||||
if (await fs.pathExists(bmmPath)) {
|
||||
return bmmPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1216,8 +1162,7 @@ class ModuleManager {
|
||||
|
||||
const installWorkflowSubPath = installMatch[2];
|
||||
|
||||
// Determine actual filesystem paths
|
||||
const sourceModulePath = path.join(this.modulesSourcePath, sourceModule);
|
||||
const sourceModulePath = getModulePath(sourceModule);
|
||||
const actualSourceWorkflowPath = path.join(sourceModulePath, 'workflows', sourceWorkflowSubPath.replace(/\/workflow\.yaml$/, ''));
|
||||
|
||||
const actualDestWorkflowPath = path.join(targetPath, 'workflows', installWorkflowSubPath.replace(/\/workflow\.yaml$/, ''));
|
||||
|
||||
@@ -55,11 +55,17 @@ function getSourcePath(...segments) {
|
||||
|
||||
/**
|
||||
* Get path to a module's directory
|
||||
* bmm is a built-in module directly under src/
|
||||
* core is also directly under src/
|
||||
* All other modules are stored remote
|
||||
*/
|
||||
function getModulePath(moduleName, ...segments) {
|
||||
if (moduleName === 'core') {
|
||||
return getSourcePath('core', ...segments);
|
||||
}
|
||||
if (moduleName === 'bmm') {
|
||||
return getSourcePath('bmm', ...segments);
|
||||
}
|
||||
return getSourcePath('modules', moduleName, ...segments);
|
||||
}
|
||||
|
||||
|
||||
@@ -512,12 +512,14 @@ class YamlXmlBuilder {
|
||||
|
||||
// Extract module from path (e.g., /path/to/modules/bmm/agents/pm.yaml -> bmm)
|
||||
// or /path/to/bmad/bmm/agents/pm.yaml -> bmm
|
||||
// or /path/to/src/bmm/agents/pm.yaml -> bmm
|
||||
let module = 'core'; // default to core
|
||||
const pathParts = agentYamlPath.split(path.sep);
|
||||
|
||||
// Look for module indicators in the path
|
||||
const modulesIndex = pathParts.indexOf('modules');
|
||||
const bmadIndex = pathParts.indexOf('bmad');
|
||||
const srcIndex = pathParts.indexOf('src');
|
||||
|
||||
if (modulesIndex !== -1 && pathParts[modulesIndex + 1]) {
|
||||
// Path contains /modules/{module}/
|
||||
@@ -529,6 +531,12 @@ class YamlXmlBuilder {
|
||||
if (['bmm', 'bmb', 'cis', 'core'].includes(potentialModule)) {
|
||||
module = potentialModule;
|
||||
}
|
||||
} else if (srcIndex !== -1 && pathParts[srcIndex + 1]) {
|
||||
// Path contains /src/{module}/ (bmm and core are directly under src/)
|
||||
const potentialModule = pathParts[srcIndex + 1];
|
||||
if (potentialModule === 'bmm' || potentialModule === 'core') {
|
||||
module = potentialModule;
|
||||
}
|
||||
}
|
||||
|
||||
// Build metadata
|
||||
|
||||
@@ -454,7 +454,7 @@ function buildMenuItemSchema() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the expected module slug from a file path residing under src/modules/<module>/agents/.
|
||||
* Derive the expected module slug from a file path residing under src/<module>/agents/.
|
||||
* @param {string} filePath Absolute or relative agent path.
|
||||
* @returns {string|null} Module slug if identifiable, otherwise null.
|
||||
*/
|
||||
@@ -463,7 +463,7 @@ function deriveModuleFromPath(filePath) {
|
||||
assert(typeof filePath === 'string', 'validateAgentFile expects filePath to be a string');
|
||||
assert(filePath.startsWith('src/'), 'validateAgentFile expects filePath to start with "src/"');
|
||||
|
||||
const marker = 'src/modules/';
|
||||
const marker = 'src/';
|
||||
if (!filePath.startsWith(marker)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
SVG_FILE="${1:-src/modules/bmm/docs/images/workflow-method-greenfield.svg}"
|
||||
SVG_FILE="${1:-src/bmm/docs/images/workflow-method-greenfield.svg}"
|
||||
TMP_DIR="/tmp/svg-validation-$$"
|
||||
|
||||
echo "🎨 Visual SVG Validation"
|
||||
|
||||
Reference in New Issue
Block a user