From 8ed36d9f0dd862d458f838849595bdab5c960e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davor=20Raci=C4=87?= Date: Sun, 1 Feb 2026 12:24:09 +0100 Subject: [PATCH] refactor: centralize BMAD_FOLDER_NAME constant in path-utils --- tools/cli/installers/lib/core/installer.js | 4 +--- tools/cli/installers/lib/ide/_base-ide.js | 5 +++-- .../lib/ide/shared/agent-command-generator.js | 4 ++-- .../installers/lib/ide/shared/path-utils.js | 4 ++++ .../ide/shared/task-tool-command-generator.js | 19 ++++++++++--------- .../ide/shared/workflow-command-generator.js | 4 ++-- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index a14c3d19..cb146270 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -17,9 +17,7 @@ const { ManifestGenerator } = require('./manifest-generator'); const { IdeConfigManager } = require('./ide-config-manager'); const { CustomHandler } = require('../custom/handler'); const prompts = require('../../../lib/prompts'); - -// BMAD installation folder name - this is constant and should never change -const BMAD_FOLDER_NAME = '_bmad'; +const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils'); class Installer { constructor() { diff --git a/tools/cli/installers/lib/ide/_base-ide.js b/tools/cli/installers/lib/ide/_base-ide.js index 8cf48601..b3ce3af3 100644 --- a/tools/cli/installers/lib/ide/_base-ide.js +++ b/tools/cli/installers/lib/ide/_base-ide.js @@ -3,6 +3,7 @@ const fs = require('fs-extra'); const chalk = require('chalk'); const { XmlHandler } = require('../../../lib/xml-handler'); const { getSourcePath } = require('../../../lib/project-root'); +const { BMAD_FOLDER_NAME } = require('./shared/path-utils'); /** * Base class for IDE-specific setup @@ -18,7 +19,7 @@ class BaseIdeSetup { this.configFile = null; // Override in subclasses when detection is file-based this.detectionPaths = []; // Additional paths that indicate the IDE is configured this.xmlHandler = new XmlHandler(); - this.bmadFolderName = '_bmad'; // Default, can be overridden + this.bmadFolderName = BMAD_FOLDER_NAME; // Default, can be overridden } /** @@ -57,7 +58,7 @@ class BaseIdeSetup { if (this.configDir) { const configPath = path.join(projectDir, this.configDir); if (await fs.pathExists(configPath)) { - const bmadRulesPath = path.join(configPath, 'bmad'); + const bmadRulesPath = path.join(configPath, BMAD_FOLDER_NAME); if (await fs.pathExists(bmadRulesPath)) { await fs.remove(bmadRulesPath); console.log(chalk.dim(`Removed ${this.name} BMAD configuration`)); diff --git a/tools/cli/installers/lib/ide/shared/agent-command-generator.js b/tools/cli/installers/lib/ide/shared/agent-command-generator.js index a0e48fbb..caf60614 100644 --- a/tools/cli/installers/lib/ide/shared/agent-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/agent-command-generator.js @@ -1,14 +1,14 @@ const path = require('node:path'); const fs = require('fs-extra'); const chalk = require('chalk'); -const { toColonPath, toDashPath, customAgentColonName, customAgentDashName } = require('./path-utils'); +const { toColonPath, toDashPath, customAgentColonName, customAgentDashName, BMAD_FOLDER_NAME } = require('./path-utils'); /** * Generates launcher command files for each agent * Similar to WorkflowCommandGenerator but for agents */ class AgentCommandGenerator { - constructor(bmadFolderName = '_bmad') { + constructor(bmadFolderName = BMAD_FOLDER_NAME) { this.templatePath = path.join(__dirname, '../templates/agent-command-template.md'); this.bmadFolderName = bmadFolderName; } diff --git a/tools/cli/installers/lib/ide/shared/path-utils.js b/tools/cli/installers/lib/ide/shared/path-utils.js index 561a9029..51966923 100644 --- a/tools/cli/installers/lib/ide/shared/path-utils.js +++ b/tools/cli/installers/lib/ide/shared/path-utils.js @@ -18,6 +18,9 @@ const TYPE_SEGMENTS = ['workflows', 'tasks', 'tools']; const AGENT_SEGMENT = 'agents'; +// BMAD installation folder name - centralized constant for all installers +const BMAD_FOLDER_NAME = '_bmad'; + /** * Convert hierarchical path to flat dash-separated name (NEW STANDARD) * Converts: 'bmm', 'agents', 'pm' → 'bmad-agent-bmm-pm.md' @@ -292,4 +295,5 @@ module.exports = { TYPE_SEGMENTS, AGENT_SEGMENT, + BMAD_FOLDER_NAME, }; diff --git a/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js b/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js index 4f1f589e..7edb130b 100644 --- a/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js @@ -2,20 +2,20 @@ const path = require('node:path'); const fs = require('fs-extra'); const csv = require('csv-parse/sync'); const chalk = require('chalk'); -const { toColonName, toColonPath, toDashPath } = require('./path-utils'); +const { toColonName, toColonPath, toDashPath, BMAD_FOLDER_NAME } = require('./path-utils'); /** * Generates command files for standalone tasks and tools */ class TaskToolCommandGenerator { /** - * @param {string} bmadFolderName - Name of the BMAD folder for template rendering (default: 'bmad') + * @param {string} bmadFolderName - Name of the BMAD folder for template rendering (default: '_bmad') * Note: This parameter is accepted for API consistency with AgentCommandGenerator and * WorkflowCommandGenerator, but is not used for path stripping. The manifest always stores * filesystem paths with '_bmad/' prefix (the actual folder name), while bmadFolderName is * used for template placeholder rendering ({{bmadFolderName}}). */ - constructor(bmadFolderName = '_bmad') { + constructor(bmadFolderName = BMAD_FOLDER_NAME) { this.bmadFolderName = bmadFolderName; } @@ -33,13 +33,14 @@ class TaskToolCommandGenerator { const standaloneTools = tools ? tools.filter((t) => t.standalone === 'true' || t.standalone === true) : []; const artifacts = []; + const bmadPrefix = `${BMAD_FOLDER_NAME}/`; // Collect task artifacts for (const task of standaloneTasks) { let taskPath = (task.path || '').replaceAll('\\', '/'); // Remove _bmad/ prefix if present to get relative path within bmad folder - if (taskPath.startsWith('_bmad/')) { - taskPath = taskPath.slice(6); // Remove '_bmad/' + if (taskPath.startsWith(bmadPrefix)) { + taskPath = taskPath.slice(bmadPrefix.length); } const taskExt = path.extname(taskPath) || '.md'; @@ -59,8 +60,8 @@ class TaskToolCommandGenerator { for (const tool of standaloneTools) { let toolPath = (tool.path || '').replaceAll('\\', '/'); // Remove _bmad/ prefix if present to get relative path within bmad folder - if (toolPath.startsWith('_bmad/')) { - toolPath = toolPath.slice(6); // Remove '_bmad/' + if (toolPath.startsWith(bmadPrefix)) { + toolPath = toolPath.slice(bmadPrefix.length); } const toolExt = path.extname(toolPath) || '.md'; @@ -159,9 +160,9 @@ class TaskToolCommandGenerator { if (bmadMatch) { // Found /_bmad/ or /bmad/ - use relative path after it itemPath = `{project-root}/${this.bmadFolderName}/${bmadMatch[1]}`; - } else if (itemPath.startsWith('_bmad/')) { + } else if (itemPath.startsWith(`${BMAD_FOLDER_NAME}/`)) { // Relative path starting with _bmad/ - itemPath = `{project-root}/${this.bmadFolderName}/${itemPath.slice(6)}`; + itemPath = `{project-root}/${this.bmadFolderName}/${itemPath.slice(BMAD_FOLDER_NAME.length + 1)}`; } else if (itemPath.startsWith('bmad/')) { // Relative path starting with bmad/ itemPath = `{project-root}/${this.bmadFolderName}/${itemPath.slice(5)}`; diff --git a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js index c3f804c4..5a23fda2 100644 --- a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js @@ -2,13 +2,13 @@ const path = require('node:path'); const fs = require('fs-extra'); const csv = require('csv-parse/sync'); const chalk = require('chalk'); -const { toColonPath, toDashPath, customAgentColonName, customAgentDashName } = require('./path-utils'); +const { toColonPath, toDashPath, customAgentColonName, customAgentDashName, BMAD_FOLDER_NAME } = require('./path-utils'); /** * Generates command files for each workflow in the manifest */ class WorkflowCommandGenerator { - constructor(bmadFolderName = '_bmad') { + constructor(bmadFolderName = BMAD_FOLDER_NAME) { this.templatePath = path.join(__dirname, '../templates/workflow-command-template.md'); this.bmadFolderName = bmadFolderName; }