installer cleanup

This commit is contained in:
Brian Madison
2026-01-23 00:27:10 -06:00
parent 3f9ad4868c
commit efbe839a0a
21 changed files with 257 additions and 325 deletions

View File

@@ -2,9 +2,9 @@
## Overview
Standardize IDE installers to use **flat file naming** and centralize duplicated code in shared utilities.
Standardize IDE installers to use **flat file naming** with **underscores** (Windows-compatible) and centralize duplicated code in shared utilities.
**Key Rule: Only folder-based IDEs convert to colon format. IDEs already using dashes keep using dashes.**
**Key Rule: All IDEs use underscore format for Windows compatibility (colons don't work on Windows).**
## Current State Analysis
@@ -15,10 +15,10 @@ Standardize IDE installers to use **flat file naming** and centralize duplicated
| **claude-code** | Hierarchical | `.claude/commands/bmad/{module}/agents/{name}.md` |
| **cursor** | Hierarchical | `.cursor/commands/bmad/{module}/agents/{name}.md` |
| **crush** | Hierarchical | `.crush/commands/bmad/{module}/agents/{name}.md` |
| **antigravity** | Flattened (dashes) | `.agent/workflows/bmad-module-agents-name.md` |
| **codex** | Flattened (dashes) | `~/.codex/prompts/bmad-module-agents-name.md` |
| **cline** | Flattened (dashes) | `.clinerules/workflows/bmad-module-type-name.md` |
| **roo** | Flattened (dashes) | `.roo/commands/bmad-{module}-agent-{name}.md` |
| **antigravity** | Flattened (underscores) | `.agent/workflows/bmad_module_agents_name.md` |
| **codex** | Flattened (underscores) | `~/.codex/prompts/bmad_module_agents_name.md` |
| **cline** | Flattened (underscores) | `.clinerules/workflows/bmad_module_type_name.md` |
| **roo** | Flattened (underscores) | `.roo/commands/bmad_module_agent_name.md` |
| **auggie** | Hybrid | `.augment/commands/bmad/agents/{module}-{name}.md` |
| **iflow** | Hybrid | `.iflow/commands/bmad/agents/{module}-{name}.md` |
| **trae** | Different (rules) | `.trae/rules/bmad-agent-{module}-{name}.md` |
@@ -40,35 +40,24 @@ All currently create artifacts with **nested relative paths** like `{module}/age
## Target Standardization
### For Folder-Based IDEs (convert to colon format)
### For All IDEs (underscore format - Windows-compatible)
**IDEs affected:** claude-code, cursor, crush
**IDEs affected:** claude-code, cursor, crush, antigravity, codex, cline, roo
```
Format: bmad:{module}:{type}:{name}.md
Format: bmad_{module}_{type}_{name}.md
Examples:
- Agent: bmad:bmm:agents:pm.md
- Agent: bmad:core:agents:dev.md
- Workflow: bmad:bmm:workflows:correct-course.md
- Task: bmad:bmm:tasks:bmad-help.md
- Tool: bmad:core:tools:code-review.md
- Custom: bmad:custom:agents:fred-commit-poet.md
- Agent: bmad_bmm_agents_pm.md
- Agent: bmad_core_agents_dev.md
- Workflow: bmad_bmm_workflows_correct-course.md
- Task: bmad_bmm_tasks_bmad-help.md
- Tool: bmad_core_tools_code-review.md
- Custom: bmad_custom_agents_fred-commit-poet.md
```
### For Already-Flat IDEs (keep using dashes)
**IDEs affected:** antigravity, codex, cline, roo
```
Format: bmad-{module}-{type}-{name}.md
Examples:
- Agent: bmad-bmm-agents-pm.md
- Workflow: bmad-bmm-workflows-correct-course.md
- Task: bmad-bmm-tasks-bmad-help.md
- Custom: bmad-custom-agents-fred-commit-poet.md
```
**Note:** Type segments (agents, workflows, tasks, tools) are filtered out from names:
- `bmm/agents/pm.md``bmad_bmm_pm.md` (not `bmad_bmm_agents_pm.md`)
### For Hybrid IDEs (keep as-is)
@@ -88,57 +77,50 @@ These use `{module}-{name}.md` format within subdirectories - keep as-is.
```javascript
/**
* Convert hierarchical path to flat colon-separated name (for folder-based IDEs)
* Convert hierarchical path to flat underscore-separated name (Windows-compatible)
* @param {string} module - Module name (e.g., 'bmm', 'core')
* @param {string} type - Artifact type ('agents', 'workflows', 'tasks', 'tools')
* @param {string} type - Artifact type ('agents', 'workflows', 'tasks', 'tools') - filtered out
* @param {string} name - Artifact name (e.g., 'pm', 'correct-course')
* @returns {string} Flat filename like 'bmad:bmm:agents:pm.md'
* @returns {string} Flat filename like 'bmad_bmm_pm.md'
*/
function toColonName(module, type, name) {
return `bmad:${module}:${type}:${name}.md`;
function toUnderscoreName(module, type, name) {
return `bmad_${module}_${name}.md`;
}
/**
* Convert relative path to flat colon-separated name (for folder-based IDEs)
* Convert relative path to flat underscore-separated name (Windows-compatible)
* @param {string} relativePath - Path like 'bmm/agents/pm.md'
* @returns {string} Flat filename like 'bmad:bmm:agents:pm.md'
* @returns {string} Flat filename like 'bmad_bmm_pm.md'
*/
function toColonPath(relativePath) {
function toUnderscorePath(relativePath) {
const withoutExt = relativePath.replace('.md', '');
const parts = withoutExt.split(/[\/\\]/);
return `bmad:${parts.join(':')}.md`;
// Filter out type segments (agents, workflows, tasks, tools)
const filtered = parts.filter((p) => !TYPE_SEGMENTS.includes(p));
return `bmad_${filtered.join('_')}.md`;
}
/**
* Convert hierarchical path to flat dash-separated name (for flat IDEs)
* @param {string} relativePath - Path like 'bmm/agents/pm.md'
* @returns {string} Flat filename like 'bmad-bmm-agents-pm.md'
*/
function toDashPath(relativePath) {
const withoutExt = relativePath.replace('.md', '');
const parts = withoutExt.split(/[\/\\]/);
return `bmad-${parts.join('-')}.md`;
}
/**
* Create custom agent colon name
* Create custom agent underscore name
* @param {string} agentName - Custom agent name
* @returns {string} Flat filename like 'bmad:custom:agents:fred-commit-poet.md'
* @returns {string} Flat filename like 'bmad_custom_fred-commit-poet.md'
*/
function customAgentColonName(agentName) {
return `bmad:custom:agents:${agentName}.md`;
function customAgentUnderscoreName(agentName) {
return `bmad_custom_${agentName}.md`;
}
/**
* Create custom agent dash name
* @param {string} agentName - Custom agent name
* @returns {string} Flat filename like 'bmad-custom-agents-fred-commit-poet.md'
*/
function customAgentDashName(agentName) {
return `bmad-custom-agents-${agentName}.md`;
}
// Backward compatibility aliases
const toColonName = toUnderscoreName;
const toColonPath = toUnderscorePath;
const toDashPath = toUnderscorePath;
const customAgentColonName = customAgentUnderscoreName;
const customAgentDashName = customAgentUnderscoreName;
module.exports = {
toUnderscoreName,
toUnderscorePath,
customAgentUnderscoreName,
// Backward compatibility
toColonName,
toColonPath,
toDashPath,
@@ -157,34 +139,26 @@ module.exports = {
**Changes:**
1. Import path utilities
2. Change `relativePath` to use flat format
3. Add method `writeColonArtifacts()` for folder-based IDEs
4. Add method `writeDashArtifacts()` for flat IDEs
3. Add method `writeColonArtifacts()` for folder-based IDEs (uses underscore)
4. Add method `writeDashArtifacts()` for flat IDEs (uses underscore)
### Phase 3: Update Folder-Based IDEs
### Phase 3: Update All IDEs
**Files to modify:**
- `claude-code.js`
- `cursor.js`
- `crush.js`
**Changes:**
1. Import `toColonPath`, `customAgentColonName` from path-utils
2. Change from hierarchical to flat colon naming
3. Update cleanup to handle flat structure
### Phase 4: Update Flat IDEs
**Files to modify:**
- `antigravity.js`
- `codex.js`
- `cline.js`
- `roo.js`
**Changes:**
1. Import `toDashPath`, `customAgentDashName` from path-utils
2. Replace local `flattenFilename()` with shared `toDashPath()`
1. Import utilities from path-utils
2. Change from hierarchical to flat underscore naming
3. Update cleanup to handle flat structure (`startsWith('bmad')`)
### Phase 5: Update Base Class
### Phase 4: Update Base Class
**File:** `_base-ide.js`
@@ -195,24 +169,23 @@ module.exports = {
## Migration Checklist
### New Files
- [ ] Create `shared/path-utils.js`
- [x] Create `shared/path-utils.js`
### Folder-Based IDEs (convert to colon format)
- [ ] Update `shared/agent-command-generator.js` - add `writeColonArtifacts()`
- [ ] Update `shared/task-tool-command-generator.js` - add `writeColonArtifacts()`
- [ ] Update `shared/workflow-command-generator.js` - add `writeColonArtifacts()`
- [ ] Update `claude-code.js` - convert to colon format
- [ ] Update `cursor.js` - convert to colon format
- [ ] Update `crush.js` - convert to colon format
### All IDEs (convert to underscore format)
- [x] Update `shared/agent-command-generator.js` - update for underscore
- [x] Update `shared/task-tool-command-generator.js` - update for underscore
- [x] Update `shared/workflow-command-generator.js` - update for underscore
- [x] Update `claude-code.js` - convert to underscore format
- [x] Update `cursor.js` - convert to underscore format
- [x] Update `crush.js` - convert to underscore format
- [ ] Update `antigravity.js` - use underscore format
- [ ] Update `codex.js` - use underscore format
- [ ] Update `cline.js` - use underscore format
- [ ] Update `roo.js` - use underscore format
### Flat IDEs (standardize dash format)
- [ ] Update `shared/agent-command-generator.js` - add `writeDashArtifacts()`
- [ ] Update `shared/task-tool-command-generator.js` - add `writeDashArtifacts()`
- [ ] Update `shared/workflow-command-generator.js` - add `writeDashArtifacts()`
- [ ] Update `antigravity.js` - use shared `toDashPath()`
- [ ] Update `codex.js` - use shared `toDashPath()`
- [ ] Update `cline.js` - use shared `toDashPath()`
- [ ] Update `roo.js` - use shared `toDashPath()`
### CSV Command Files
- [x] Update `src/core/module-help.csv` - change colons to underscores
- [x] Update `src/bmm/module-help.csv` - change colons to underscores
### Base Class
- [ ] Update `_base-ide.js` - add deprecation notice
@@ -228,7 +201,8 @@ module.exports = {
## Notes
1. **Keep segments**: agents, workflows, tasks, tools all become part of the flat name
2. **Colon vs Dash**: Colons for folder-based IDEs converting to flat, dashes for already-flat IDEs
1. **Filter type segments**: agents, workflows, tasks, tools are filtered out from flat names
2. **Underscore format**: Universal underscore format for Windows compatibility
3. **Custom agents**: Follow the same pattern as regular agents
4. **Backward compatibility**: Cleanup will remove old folder structure
4. **Backward compatibility**: Old function names kept as aliases
5. **Cleanup**: Will remove old `bmad:` format files on next install

View File

@@ -127,8 +127,8 @@ class AntigravitySetup extends BaseIdeSetup {
const { artifacts: agentArtifacts, counts: agentCounts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Write agent launcher files with FLATTENED naming using shared utility
// Antigravity ignores directory structure, so we flatten to: bmad-module-name.md
// This creates slash commands like /bmad-bmm-dev instead of /dev
// Antigravity ignores directory structure, so we flatten to: bmad_module_name.md
// This creates slash commands like /bmad_bmm_dev instead of /dev
const agentCount = await agentGen.writeDashArtifacts(bmadWorkflowsDir, agentArtifacts);
// Process Antigravity specific injections for installed modules
@@ -167,7 +167,7 @@ class AntigravitySetup extends BaseIdeSetup {
);
}
console.log(chalk.dim(` - Workflows directory: ${path.relative(projectDir, bmadWorkflowsDir)}`));
console.log(chalk.yellow(`\n Note: Antigravity uses flattened slash commands (e.g., /bmad-module-agents-name)`));
console.log(chalk.yellow(`\n Note: Antigravity uses flattened slash commands (e.g., /bmad_module_agents_name)`));
return {
success: true,
@@ -455,7 +455,7 @@ usage: |
⚠️ **IMPORTANT**: Run @${agentPath} to load the complete agent before using this launcher!`;
// Use dash format: bmad-custom-agents-fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
const fileName = customAgentDashName(agentName);
const launcherPath = path.join(bmadWorkflowsDir, fileName);

View File

@@ -92,12 +92,12 @@ class ClaudeCodeSetup extends BaseIdeSetup {
async cleanup(projectDir) {
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
// Remove any bmad:* files from the commands directory
// Remove any bmad* files from the commands directory (cleans up old bmad: and bmad- formats)
if (await fs.pathExists(commandsDir)) {
const entries = await fs.readdir(commandsDir);
let removedCount = 0;
for (const entry of entries) {
if (entry.startsWith('bmad:')) {
if (entry.startsWith('bmad')) {
await fs.remove(path.join(commandsDir, entry));
removedCount++;
}
@@ -151,16 +151,16 @@ class ClaudeCodeSetup extends BaseIdeSetup {
const commandsDir = path.join(claudeDir, this.commandsDir);
await this.ensureDir(commandsDir);
// Use colon format: files written directly to commands dir (no bmad subfolder)
// Creates: .claude/commands/bmad:bmm:pm.md
// Use underscore format: files written directly to commands dir (no bmad subfolder)
// Creates: .claude/commands/bmad_bmm_pm.md
// Generate agent launchers using AgentCommandGenerator
// This creates small launcher files that reference the actual agents in _bmad/
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts, counts: agentCounts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Write agent launcher files using flat colon naming
// Creates files like: bmad:bmm:pm.md
// Write agent launcher files using flat underscore naming
// Creates files like: bmad_bmm_pm.md
const agentCount = await agentGen.writeColonArtifacts(commandsDir, agentArtifacts);
// Process Claude Code specific injections for installed modules
@@ -182,8 +182,8 @@ class ClaudeCodeSetup extends BaseIdeSetup {
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
// Write workflow-command artifacts using flat colon naming
// Creates files like: bmad:bmm:correct-course.md
// Write workflow-command artifacts using flat underscore naming
// Creates files like: bmad_bmm_correct-course.md
const workflowCommandCount = await workflowGen.writeColonArtifacts(commandsDir, workflowArtifacts);
// Generate task and tool commands from manifests (if they exist)
@@ -490,7 +490,7 @@ You must fully embody this agent's persona and follow all activation instruction
</agent-activation>
`;
// Use colon format: bmad:custom:agents:fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
// Written directly to commands dir (no bmad subfolder)
const launcherName = customAgentColonName(agentName);
const launcherPath = path.join(commandsDir, launcherName);

View File

@@ -57,8 +57,8 @@ class ClineSetup extends BaseIdeSetup {
console.log(chalk.cyan(' BMAD workflows are available as slash commands in Cline'));
console.log(chalk.dim(' Usage:'));
console.log(chalk.dim(' - Type / to see available commands'));
console.log(chalk.dim(' - All BMAD items start with "bmad-"'));
console.log(chalk.dim(' - Example: /bmad-bmm-pm'));
console.log(chalk.dim(' - All BMAD items start with "bmad_"'));
console.log(chalk.dim(' - Example: /bmad_bmm_pm'));
return {
success: true,
@@ -81,7 +81,7 @@ class ClineSetup extends BaseIdeSetup {
}
const entries = await fs.readdir(workflowsDir);
return entries.some((entry) => entry.startsWith('bmad-'));
return entries.some((entry) => entry.startsWith('bmad'));
}
/**
@@ -146,7 +146,7 @@ class ClineSetup extends BaseIdeSetup {
}
/**
* Flatten file path to bmad-module-type-name.md format
* Flatten file path to bmad_module_type_name.md format
* Uses shared toDashPath utility
*/
flattenFilename(relativePath) {
@@ -180,7 +180,7 @@ class ClineSetup extends BaseIdeSetup {
const entries = await fs.readdir(destDir);
for (const entry of entries) {
if (!entry.startsWith('bmad-')) {
if (!entry.startsWith('bmad')) {
continue;
}
@@ -246,7 +246,7 @@ The agent will follow the persona and instructions from the main agent file.
*Generated by BMAD Method*`;
// Use dash format: bmad-custom-agents-fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
const fileName = customAgentDashName(agentName);
const launcherPath = path.join(workflowsDir, fileName);

View File

@@ -86,7 +86,7 @@ class CodexSetup extends BaseIdeSetup {
await fs.ensureDir(destDir);
await this.clearOldBmadFiles(destDir);
// Collect artifacts and write using DASH format
// Collect artifacts and write using underscore format
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
const agentCount = await agentGen.writeDashArtifacts(destDir, agentArtifacts);
@@ -115,7 +115,7 @@ class CodexSetup extends BaseIdeSetup {
const { artifacts: workflowArtifacts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
const workflowCount = await workflowGenerator.writeDashArtifacts(destDir, workflowArtifacts);
// Also write tasks using dash format
// Also write tasks using underscore format
const ttGen = new TaskToolCommandGenerator();
const tasksWritten = await ttGen.writeDashArtifacts(destDir, taskArtifacts);
@@ -155,7 +155,7 @@ class CodexSetup extends BaseIdeSetup {
// Check global location
if (await fs.pathExists(globalDir)) {
const entries = await fs.readdir(globalDir);
if (entries.some((entry) => entry.startsWith('bmad-'))) {
if (entries.some((entry) => entry.startsWith('bmad'))) {
return true;
}
}
@@ -163,7 +163,7 @@ class CodexSetup extends BaseIdeSetup {
// Check project-specific location
if (await fs.pathExists(projectSpecificDir)) {
const entries = await fs.readdir(projectSpecificDir);
if (entries.some((entry) => entry.startsWith('bmad-'))) {
if (entries.some((entry) => entry.startsWith('bmad'))) {
return true;
}
}
@@ -256,7 +256,7 @@ class CodexSetup extends BaseIdeSetup {
const entries = await fs.readdir(destDir);
for (const entry of entries) {
if (!entry.startsWith('bmad-')) {
if (!entry.startsWith('bmad')) {
continue;
}
@@ -292,7 +292,7 @@ class CodexSetup extends BaseIdeSetup {
chalk.dim(" To use with other projects, you'd need to copy the _bmad dir"),
'',
chalk.green(' ✓ You can now use /commands in Codex CLI'),
chalk.dim(' Example: /bmad-bmm-pm'),
chalk.dim(' Example: /bmad_bmm_pm'),
chalk.dim(' Type / to see all available commands'),
'',
chalk.bold.cyan('═'.repeat(70)),
@@ -397,7 +397,7 @@ You must fully embody this agent's persona and follow all activation instruction
</agent-activation>
`;
// Use dash format: bmad-custom-agents-fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
const fileName = customAgentDashName(agentName);
const launcherPath = path.join(destDir, fileName);
await fs.writeFile(launcherPath, launcherContent, 'utf8');

View File

@@ -35,26 +35,26 @@ class CrushSetup extends BaseIdeSetup {
const commandsDir = path.join(crushDir, this.commandsDir);
await this.ensureDir(commandsDir);
// Use colon format: files written directly to commands dir (no bmad subfolder)
// Creates: .crush/commands/bmad:bmm:pm.md
// Use underscore format: files written directly to commands dir (no bmad subfolder)
// Creates: .crush/commands/bmad_bmm_pm.md
// Generate agent launchers
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Write agent launcher files using flat colon naming
// Creates files like: bmad:bmm:pm.md
// Write agent launcher files using flat underscore naming
// Creates files like: bmad_bmm_pm.md
const agentCount = await agentGen.writeColonArtifacts(commandsDir, agentArtifacts);
// Get ALL workflows using the new workflow command generator
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
// Write workflow-command artifacts using flat colon naming
// Creates files like: bmad:bmm:correct-course.md
// Write workflow-command artifacts using flat underscore naming
// Creates files like: bmad_bmm_correct-course.md
const workflowCount = await workflowGenerator.writeColonArtifacts(commandsDir, workflowArtifacts);
// Generate task and tool commands using flat colon naming
// Generate task and tool commands using flat underscore naming
const taskToolGen = new TaskToolCommandGenerator();
const taskToolResult = await taskToolGen.generateColonTaskToolCommands(projectDir, bmadDir, commandsDir);
@@ -81,11 +81,11 @@ class CrushSetup extends BaseIdeSetup {
async cleanup(projectDir) {
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
// Remove any bmad:* files from the commands directory
// Remove any bmad* files from the commands directory (cleans up old bmad: and bmad- formats)
if (await fs.pathExists(commandsDir)) {
const entries = await fs.readdir(commandsDir);
for (const entry of entries) {
if (entry.startsWith('bmad:')) {
if (entry.startsWith('bmad')) {
await fs.remove(path.join(commandsDir, entry));
}
}
@@ -129,7 +129,7 @@ The agent will follow the persona and instructions from the main agent file.
*Generated by BMAD Method*`;
// Use colon format: bmad:custom:agents:fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
// Written directly to commands dir (no bmad subfolder)
const launcherName = customAgentColonName(agentName);
const launcherPath = path.join(commandsDir, launcherName);

View File

@@ -25,11 +25,11 @@ class CursorSetup extends BaseIdeSetup {
const fs = require('fs-extra');
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
// Remove any bmad:* files from the commands directory
// Remove any bmad* files from the commands directory (cleans up old bmad: and bmad- formats)
if (await fs.pathExists(commandsDir)) {
const entries = await fs.readdir(commandsDir);
for (const entry of entries) {
if (entry.startsWith('bmad:')) {
if (entry.startsWith('bmad')) {
await fs.remove(path.join(commandsDir, entry));
}
}
@@ -59,24 +59,24 @@ class CursorSetup extends BaseIdeSetup {
const commandsDir = path.join(cursorDir, this.commandsDir);
await this.ensureDir(commandsDir);
// Use colon format: files written directly to commands dir (no bmad subfolder)
// Creates: .cursor/commands/bmad:bmm:pm.md
// Use underscore format: files written directly to commands dir (no bmad subfolder)
// Creates: .cursor/commands/bmad_bmm_pm.md
// Generate agent launchers using AgentCommandGenerator
// This creates small launcher files that reference the actual agents in _bmad/
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts, counts: agentCounts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Write agent launcher files using flat colon naming
// Creates files like: bmad:bmm:pm.md
// Write agent launcher files using flat underscore naming
// Creates files like: bmad_bmm_pm.md
const agentCount = await agentGen.writeColonArtifacts(commandsDir, agentArtifacts);
// Generate workflow commands from manifest (if it exists)
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
// Write workflow-command artifacts using flat colon naming
// Creates files like: bmad:bmm:correct-course.md
// Write workflow-command artifacts using flat underscore naming
// Creates files like: bmad_bmm_correct-course.md
const workflowCommandCount = await workflowGen.writeColonArtifacts(commandsDir, workflowArtifacts);
// Generate task and tool commands from manifests (if they exist)
@@ -144,7 +144,7 @@ description: '${agentName} agent'
${launcherContent}
`;
// Use colon format: bmad:custom:agents:fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
// Written directly to commands dir (no bmad subfolder)
const launcherName = customAgentColonName(agentName);
const launcherPath = path.join(commandsDir, launcherName);

View File

@@ -86,7 +86,7 @@ class GeminiSetup extends BaseIdeSetup {
await this.writeFile(tomlPath, tomlContent);
agentCount++;
console.log(chalk.green(` ✓ Added agent: /bmad:agents:${artifact.module}:${artifact.name}`));
console.log(chalk.green(` ✓ Added agent: /bmad_agents_${artifact.module}_${artifact.name}`));
}
// Install tasks as TOML files with bmad- prefix (flat structure)
@@ -100,7 +100,7 @@ class GeminiSetup extends BaseIdeSetup {
await this.writeFile(tomlPath, tomlContent);
taskCount++;
console.log(chalk.green(` ✓ Added task: /bmad:tasks:${task.module}:${task.name}`));
console.log(chalk.green(` ✓ Added task: /bmad_tasks_${task.module}_${task.name}`));
}
// Install workflows as TOML files with bmad- prefix (flat structure)
@@ -116,7 +116,7 @@ class GeminiSetup extends BaseIdeSetup {
await this.writeFile(tomlPath, tomlContent);
workflowCount++;
console.log(chalk.green(` ✓ Added workflow: /bmad:workflows:${artifact.module}:${workflowName}`));
console.log(chalk.green(` ✓ Added workflow: /bmad_workflows_${artifact.module}_${workflowName}`));
}
}
@@ -125,9 +125,9 @@ class GeminiSetup extends BaseIdeSetup {
console.log(chalk.dim(` - ${taskCount} tasks configured`));
console.log(chalk.dim(` - ${workflowCount} workflows configured`));
console.log(chalk.dim(` - Commands directory: ${path.relative(projectDir, commandsDir)}`));
console.log(chalk.dim(` - Agent activation: /bmad:agents:{agent-name}`));
console.log(chalk.dim(` - Task activation: /bmad:tasks:{task-name}`));
console.log(chalk.dim(` - Workflow activation: /bmad:workflows:{workflow-name}`));
console.log(chalk.dim(` - Agent activation: /bmad_agents_{agent-name}`));
console.log(chalk.dim(` - Task activation: /bmad_tasks_{task-name}`));
console.log(chalk.dim(` - Workflow activation: /bmad_workflows_{workflow-name}`));
return {
success: true,
@@ -233,12 +233,12 @@ ${contentWithoutFrontmatter}
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
if (await fs.pathExists(commandsDir)) {
// Only remove files that start with bmad- prefix
// Remove any bmad* files (cleans up old bmad- and bmad: formats)
const files = await fs.readdir(commandsDir);
let removed = 0;
for (const file of files) {
if (file.startsWith('bmad-') && file.endsWith('.toml')) {
if (file.startsWith('bmad') && file.endsWith('.toml')) {
await fs.remove(path.join(commandsDir, file));
removed++;
}

View File

@@ -275,7 +275,7 @@ ${cleanContent}
let removed = 0;
for (const file of files) {
if (file.startsWith('bmad-') && file.endsWith('.chatmode.md')) {
if (file.startsWith('bmad') && file.endsWith('.chatmode.md')) {
await fs.remove(path.join(chatmodesDir, file));
removed++;
}

View File

@@ -25,7 +25,7 @@ class KiroCliSetup extends BaseIdeSetup {
// Remove existing BMad agents
const files = await fs.readdir(bmadAgentsDir);
for (const file of files) {
if (file.startsWith('bmad-') || file.includes('bmad')) {
if (file.startsWith('bmad')) {
await fs.remove(path.join(bmadAgentsDir, file));
}
}

View File

@@ -185,7 +185,7 @@ class OpenCodeSetup extends BaseIdeSetup {
if (await fs.pathExists(agentsDir)) {
const files = await fs.readdir(agentsDir);
for (const file of files) {
if (file.startsWith('bmad-') && file.endsWith('.md')) {
if (file.startsWith('bmad') && file.endsWith('.md')) {
await fs.remove(path.join(agentsDir, file));
removed++;
}
@@ -196,7 +196,7 @@ class OpenCodeSetup extends BaseIdeSetup {
if (await fs.pathExists(commandsDir)) {
const files = await fs.readdir(commandsDir);
for (const file of files) {
if (file.startsWith('bmad-') && file.endsWith('.md')) {
if (file.startsWith('bmad') && file.endsWith('.md')) {
await fs.remove(path.join(commandsDir, file));
removed++;
}

View File

@@ -74,7 +74,7 @@ class QwenSetup extends BaseIdeSetup {
await this.writeFile(targetPath, tomlContent);
agentCount++;
console.log(chalk.green(` ✓ Added agent: /bmad:${artifact.module}:agents:${artifact.name}`));
console.log(chalk.green(` ✓ Added agent: /bmad_${artifact.module}_agents_${artifact.name}`));
}
// Create TOML files for each task
@@ -90,7 +90,7 @@ class QwenSetup extends BaseIdeSetup {
await this.writeFile(targetPath, content);
taskCount++;
console.log(chalk.green(` ✓ Added task: /bmad:${task.module}:tasks:${task.name}`));
console.log(chalk.green(` ✓ Added task: /bmad_${task.module}_tasks_${task.name}`));
}
// Create TOML files for each tool
@@ -106,7 +106,7 @@ class QwenSetup extends BaseIdeSetup {
await this.writeFile(targetPath, content);
toolCount++;
console.log(chalk.green(` ✓ Added tool: /bmad:${tool.module}:tools:${tool.name}`));
console.log(chalk.green(` ✓ Added tool: /bmad_${tool.module}_tools_${tool.name}`));
}
// Create TOML files for each workflow
@@ -122,7 +122,7 @@ class QwenSetup extends BaseIdeSetup {
await this.writeFile(targetPath, content);
workflowCount++;
console.log(chalk.green(` ✓ Added workflow: /bmad:${workflow.module}:workflows:${workflow.name}`));
console.log(chalk.green(` ✓ Added workflow: /bmad_${workflow.module}_workflows_${workflow.name}`));
}
console.log(chalk.green(`${this.name} configured:`));

View File

@@ -36,7 +36,7 @@ class RooSetup extends BaseIdeSetup {
let skippedCount = 0;
for (const artifact of agentArtifacts) {
// Use shared toDashPath to get consistent naming: bmad-bmm-name.md
// Use shared toDashPath to get consistent naming: bmad_bmm_name.md
const commandName = toDashPath(artifact.relativePath).replace('.md', '');
const commandPath = path.join(rooCommandsDir, `${commandName}.md`);
@@ -169,7 +169,7 @@ class RooSetup extends BaseIdeSetup {
let removedCount = 0;
for (const file of files) {
if (file.startsWith('bmad-') && file.endsWith('.md')) {
if (file.startsWith('bmad') && file.endsWith('.md')) {
await fs.remove(path.join(rooCommandsDir, file));
removedCount++;
}
@@ -192,7 +192,7 @@ class RooSetup extends BaseIdeSetup {
let removedCount = 0;
for (const line of lines) {
if (/^\s*- slug: bmad-/.test(line)) {
if (/^\s*- slug: bmad/.test(line)) {
skipMode = true;
removedCount++;
} else if (skipMode && /^\s*- slug: /.test(line)) {
@@ -224,7 +224,7 @@ class RooSetup extends BaseIdeSetup {
const rooCommandsDir = path.join(projectDir, this.configDir, this.commandsDir);
await this.ensureDir(rooCommandsDir);
// Use dash format: bmad-custom-agents-fred-commit-poet.md
// Use underscore format: bmad_custom_fred-commit-poet.md
const commandName = customAgentDashName(agentName).replace('.md', '');
const commandPath = path.join(rooCommandsDir, `${commandName}.md`);

View File

@@ -37,7 +37,7 @@ class RovoDevSetup extends BaseIdeSetup {
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
if (await fs.pathExists(subagentsDir)) {
const entries = await fs.readdir(subagentsDir);
const bmadFiles = entries.filter((file) => file.startsWith('bmad-') && file.endsWith('.md'));
const bmadFiles = entries.filter((file) => file.startsWith('bmad') && file.endsWith('.md'));
for (const file of bmadFiles) {
await fs.remove(path.join(subagentsDir, file));
@@ -48,7 +48,7 @@ class RovoDevSetup extends BaseIdeSetup {
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
if (await fs.pathExists(workflowsDir)) {
const entries = await fs.readdir(workflowsDir);
const bmadFiles = entries.filter((file) => file.startsWith('bmad-') && file.endsWith('.md'));
const bmadFiles = entries.filter((file) => file.startsWith('bmad') && file.endsWith('.md'));
for (const file of bmadFiles) {
await fs.remove(path.join(workflowsDir, file));
@@ -59,7 +59,7 @@ class RovoDevSetup extends BaseIdeSetup {
const referencesDir = path.join(rovoDevDir, this.referencesDir);
if (await fs.pathExists(referencesDir)) {
const entries = await fs.readdir(referencesDir);
const bmadFiles = entries.filter((file) => file.startsWith('bmad-') && file.endsWith('.md'));
const bmadFiles = entries.filter((file) => file.startsWith('bmad') && file.endsWith('.md'));
for (const file of bmadFiles) {
await fs.remove(path.join(referencesDir, file));
@@ -249,7 +249,7 @@ class RovoDevSetup extends BaseIdeSetup {
if (await fs.pathExists(subagentsDir)) {
try {
const entries = await fs.readdir(subagentsDir);
if (entries.some((entry) => entry.startsWith('bmad-') && entry.endsWith('.md'))) {
if (entries.some((entry) => entry.startsWith('bmad') && entry.endsWith('.md'))) {
return true;
}
} catch {
@@ -262,7 +262,7 @@ class RovoDevSetup extends BaseIdeSetup {
if (await fs.pathExists(workflowsDir)) {
try {
const entries = await fs.readdir(workflowsDir);
if (entries.some((entry) => entry.startsWith('bmad-') && entry.endsWith('.md'))) {
if (entries.some((entry) => entry.startsWith('bmad') && entry.endsWith('.md'))) {
return true;
}
} catch {
@@ -275,7 +275,7 @@ class RovoDevSetup extends BaseIdeSetup {
if (await fs.pathExists(referencesDir)) {
try {
const entries = await fs.readdir(referencesDir);
if (entries.some((entry) => entry.startsWith('bmad-') && entry.endsWith('.md'))) {
if (entries.some((entry) => entry.startsWith('bmad') && entry.endsWith('.md'))) {
return true;
}
} catch {

View File

@@ -94,8 +94,8 @@ class AgentCommandGenerator {
}
/**
* Write agent launcher artifacts using COLON format (for folder-based IDEs)
* Creates flat files like: bmad:bmm:pm.md
* Write agent launcher artifacts using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_pm.md
*
* @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Agent launcher artifacts
@@ -106,7 +106,7 @@ class AgentCommandGenerator {
for (const artifact of artifacts) {
if (artifact.type === 'agent-launcher') {
// Convert relativePath to colon format: bmm/agents/pm.md → bmad:bmm:pm.md
// Convert relativePath to underscore format: bmm/agents/pm.md → bmad_bmm_pm.md
const flatName = toColonPath(artifact.relativePath);
const launcherPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(launcherPath));
@@ -119,8 +119,8 @@ class AgentCommandGenerator {
}
/**
* Write agent launcher artifacts using DASH format (for flat IDEs)
* Creates flat files like: bmad-bmm-pm.md
* Write agent launcher artifacts using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_pm.md
*
* @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Agent launcher artifacts
@@ -131,7 +131,7 @@ class AgentCommandGenerator {
for (const artifact of artifacts) {
if (artifact.type === 'agent-launcher') {
// Convert relativePath to dash format: bmm/agents/pm.md → bmad-bmm-pm.md
// Convert relativePath to underscore format: bmm/agents/pm.md → bmad_bmm_pm.md
const flatName = toDashPath(artifact.relativePath);
const launcherPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(launcherPath));
@@ -144,18 +144,18 @@ class AgentCommandGenerator {
}
/**
* Get the custom agent name in colon format
* Get the custom agent name in underscore format (Windows-compatible)
* @param {string} agentName - Custom agent name
* @returns {string} Colon-formatted filename
* @returns {string} Underscore-formatted filename
*/
getCustomAgentColonName(agentName) {
return customAgentColonName(agentName);
}
/**
* Get the custom agent name in dash format
* Get the custom agent name in underscore format (Windows-compatible)
* @param {string} agentName - Custom agent name
* @returns {string} Dash-formatted filename
* @returns {string} Underscore-formatted filename
*/
getCustomAgentDashName(agentName) {
return customAgentDashName(agentName);

View File

@@ -2,109 +2,72 @@
* Path transformation utilities for IDE installer standardization
*
* Provides utilities to convert hierarchical paths to flat naming conventions.
* - Colon format (bmad:module:name.md) for folder-based IDEs converting to flat
* - Dash format (bmad-module-name.md) for already-flat IDEs
* - Underscore format (bmad_module_name.md) - Windows-compatible universal format
*/
// Type segments to filter out from paths
const TYPE_SEGMENTS = ['agents', 'workflows', 'tasks', 'tools'];
/**
* Convert hierarchical path to flat colon-separated name (for folder-based IDEs)
* Converts: 'bmm/agents/pm.md' → 'bmad:bmm:pm.md'
* Converts: 'bmm/workflows/correct-course.md' → 'bmad:bmm:correct-course.md'
* Convert hierarchical path to flat underscore-separated name
* Converts: 'bmm/agents/pm.md' → 'bmad_bmm_pm.md'
* Converts: 'bmm/workflows/correct-course.md' → 'bmad_bmm_correct-course.md'
*
* @param {string} module - Module name (e.g., 'bmm', 'core')
* @param {string} type - Artifact type ('agents', 'workflows', 'tasks', 'tools') - filtered out
* @param {string} name - Artifact name (e.g., 'pm', 'correct-course')
* @returns {string} Flat filename like 'bmad:bmm:pm.md'
* @returns {string} Flat filename like 'bmad_bmm_pm.md'
*/
function toColonName(module, type, name) {
return `bmad:${module}:${name}.md`;
function toUnderscoreName(module, type, name) {
return `bmad_${module}_${name}.md`;
}
/**
* Convert relative path to flat colon-separated name (for folder-based IDEs)
* Converts: 'bmm/agents/pm.md' → 'bmad:bmm:pm.md'
* Converts: 'bmm/workflows/correct-course.md' → 'bmad:bmm:correct-course.md'
* Convert relative path to flat underscore-separated name
* Converts: 'bmm/agents/pm.md' → 'bmad_bmm_pm.md'
* Converts: 'bmm/workflows/correct-course.md' → 'bmad_bmm_correct-course.md'
*
* @param {string} relativePath - Path like 'bmm/agents/pm.md'
* @returns {string} Flat filename like 'bmad:bmm:pm.md'
* @returns {string} Flat filename like 'bmad_bmm_pm.md'
*/
function toColonPath(relativePath) {
function toUnderscorePath(relativePath) {
const withoutExt = relativePath.replace('.md', '');
const parts = withoutExt.split(/[/\\]/);
// Filter out type segments (agents, workflows, tasks, tools)
const filtered = parts.filter((p) => !TYPE_SEGMENTS.includes(p));
return `bmad:${filtered.join(':')}.md`;
return `bmad_${filtered.join('_')}.md`;
}
/**
* Convert hierarchical path to flat dash-separated name (for flat IDEs)
* Converts: 'bmm/agents/pm.md' → 'bmad-bmm-pm.md'
* Converts: 'bmm/workflows/correct-course.md' → 'bmad-bmm-correct-course.md'
*
* @param {string} relativePath - Path like 'bmm/agents/pm.md'
* @returns {string} Flat filename like 'bmad-bmm-pm.md'
*/
function toDashPath(relativePath) {
const withoutExt = relativePath.replace('.md', '');
const parts = withoutExt.split(/[/\\]/);
// Filter out type segments (agents, workflows, tasks, tools)
const filtered = parts.filter((p) => !TYPE_SEGMENTS.includes(p));
return `bmad-${filtered.join('-')}.md`;
}
/**
* Create custom agent colon name (for folder-based IDEs)
* Creates: 'bmad:custom:fred-commit-poet.md'
* Create custom agent underscore name
* Creates: 'bmad_custom_fred-commit-poet.md'
*
* @param {string} agentName - Custom agent name
* @returns {string} Flat filename like 'bmad:custom:fred-commit-poet.md'
* @returns {string} Flat filename like 'bmad_custom_fred-commit-poet.md'
*/
function customAgentColonName(agentName) {
return `bmad:custom:${agentName}.md`;
function customAgentUnderscoreName(agentName) {
return `bmad_custom_${agentName}.md`;
}
/**
* Create custom agent dash name (for flat IDEs)
* Creates: 'bmad-custom-fred-commit-poet.md'
*
* @param {string} agentName - Custom agent name
* @returns {string} Flat filename like 'bmad-custom-fred-commit-poet.md'
*/
function customAgentDashName(agentName) {
return `bmad-custom-${agentName}.md`;
}
/**
* Check if a filename uses colon format
* Check if a filename uses underscore format
* @param {string} filename - Filename to check
* @returns {boolean} True if filename uses colon format
* @returns {boolean} True if filename uses underscore format
*/
function isColonFormat(filename) {
return filename.includes('bmad:') && filename.includes(':');
function isUnderscoreFormat(filename) {
return filename.startsWith('bmad_') && filename.includes('_');
}
/**
* Check if a filename uses dash format
* @param {string} filename - Filename to check
* @returns {boolean} True if filename uses dash format
*/
function isDashFormat(filename) {
return filename.startsWith('bmad-') && !filename.includes(':');
}
/**
* Extract parts from a colon-formatted filename
* Parses: 'bmad:bmm:pm.md' → { prefix: 'bmad', module: 'bmm', name: 'pm' }
* Extract parts from an underscore-formatted filename
* Parses: 'bmad_bmm_pm.md' → { prefix: 'bmad', module: 'bmm', name: 'pm' }
*
* @param {string} filename - Colon-formatted filename
* @param {string} filename - Underscore-formatted filename
* @returns {Object|null} Parsed parts or null if invalid format
*/
function parseColonName(filename) {
function parseUnderscoreName(filename) {
const withoutExt = filename.replace('.md', '');
const parts = withoutExt.split(':');
const parts = withoutExt.split('_');
if (parts.length < 3 || parts[0] !== 'bmad') {
return null;
@@ -113,33 +76,28 @@ function parseColonName(filename) {
return {
prefix: parts[0],
module: parts[1],
name: parts.slice(2).join(':'), // Handle names that might contain colons
name: parts.slice(2).join('_'), // Handle names that might contain underscores
};
}
/**
* Extract parts from a dash-formatted filename
* Parses: 'bmad-bmm-pm.md' → { prefix: 'bmad', module: 'bmm', name: 'pm' }
*
* @param {string} filename - Dash-formatted filename
* @returns {Object|null} Parsed parts or null if invalid format
*/
function parseDashName(filename) {
const withoutExt = filename.replace('.md', '');
const parts = withoutExt.split('-');
if (parts.length < 3 || parts[0] !== 'bmad') {
return null;
}
return {
prefix: parts[0],
module: parts[1],
name: parts.slice(2).join('-'), // Handle names that might contain dashes
};
}
// Backward compatibility aliases (deprecated)
const toColonName = toUnderscoreName;
const toColonPath = toUnderscorePath;
const toDashPath = toUnderscorePath;
const customAgentColonName = customAgentUnderscoreName;
const customAgentDashName = customAgentUnderscoreName;
const isColonFormat = isUnderscoreFormat;
const isDashFormat = isUnderscoreFormat;
const parseColonName = parseUnderscoreName;
const parseDashName = parseUnderscoreName;
module.exports = {
toUnderscoreName,
toUnderscorePath,
customAgentUnderscoreName,
isUnderscoreFormat,
parseUnderscoreName,
// Backward compatibility aliases
toColonName,
toColonPath,
toDashPath,

View File

@@ -117,8 +117,8 @@ Follow all instructions in the ${type} file exactly as written.
}
/**
* Generate task and tool commands using COLON format (for folder-based IDEs)
* Creates flat files like: bmad:bmm:bmad-help.md
* Generate task and tool commands using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_bmad-help.md
*
* @param {string} projectDir - Project directory
* @param {string} bmadDir - BMAD installation directory
@@ -138,7 +138,7 @@ Follow all instructions in the ${type} file exactly as written.
// Generate command files for tasks
for (const task of standaloneTasks) {
const commandContent = this.generateCommandContent(task, 'task');
// Use colon format: bmad:bmm:name.md
// Use underscore format: bmad_bmm_name.md
const flatName = toColonName(task.module, 'tasks', task.name);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));
@@ -149,7 +149,7 @@ Follow all instructions in the ${type} file exactly as written.
// Generate command files for tools
for (const tool of standaloneTools) {
const commandContent = this.generateCommandContent(tool, 'tool');
// Use colon format: bmad:bmm:name.md
// Use underscore format: bmad_bmm_name.md
const flatName = toColonName(tool.module, 'tools', tool.name);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));
@@ -165,8 +165,8 @@ Follow all instructions in the ${type} file exactly as written.
}
/**
* Generate task and tool commands using DASH format (for flat IDEs)
* Creates flat files like: bmad-bmm-bmad-help.md
* Generate task and tool commands using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_bmad-help.md
*
* @param {string} projectDir - Project directory
* @param {string} bmadDir - BMAD installation directory
@@ -186,7 +186,7 @@ Follow all instructions in the ${type} file exactly as written.
// Generate command files for tasks
for (const task of standaloneTasks) {
const commandContent = this.generateCommandContent(task, 'task');
// Use dash format: bmad-bmm-name.md
// Use underscore format: bmad_bmm_name.md
const flatName = toDashPath(`${task.module}/tasks/${task.name}.md`);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));
@@ -197,7 +197,7 @@ Follow all instructions in the ${type} file exactly as written.
// Generate command files for tools
for (const tool of standaloneTools) {
const commandContent = this.generateCommandContent(tool, 'tool');
// Use dash format: bmad-bmm-name.md
// Use underscore format: bmad_bmm_name.md
const flatName = toDashPath(`${tool.module}/tools/${tool.name}.md`);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));
@@ -213,8 +213,8 @@ Follow all instructions in the ${type} file exactly as written.
}
/**
* Write task/tool artifacts using COLON format (for folder-based IDEs)
* Creates flat files like: bmad:bmm:bmad-help.md
* Write task/tool artifacts using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_bmad-help.md
*
* @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Task/tool artifacts with relativePath
@@ -226,7 +226,7 @@ Follow all instructions in the ${type} file exactly as written.
for (const artifact of artifacts) {
if (artifact.type === 'task' || artifact.type === 'tool') {
const commandContent = this.generateCommandContent(artifact, artifact.type);
// Use colon format: bmad:module:name.md
// Use underscore format: bmad_module_name.md
const flatName = toColonPath(artifact.relativePath);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));
@@ -239,8 +239,8 @@ Follow all instructions in the ${type} file exactly as written.
}
/**
* Write task/tool artifacts using DASH format (for flat IDEs)
* Creates flat files like: bmad-bmm-bmad-help.md
* Write task/tool artifacts using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_bmad-help.md
*
* @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Task/tool artifacts with relativePath
@@ -252,7 +252,7 @@ Follow all instructions in the ${type} file exactly as written.
for (const artifact of artifacts) {
if (artifact.type === 'task' || artifact.type === 'tool') {
const commandContent = this.generateCommandContent(artifact, artifact.type);
// Use dash format: bmad-module-name.md
// Use underscore format: bmad_module_name.md
const flatName = toDashPath(artifact.relativePath);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));

View File

@@ -240,8 +240,8 @@ When running any workflow:
}
/**
* Write workflow command artifacts using COLON format (for folder-based IDEs)
* Creates flat files like: bmad:bmm:correct-course.md
* Write workflow command artifacts using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_correct-course.md
*
* @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Workflow artifacts
@@ -252,7 +252,7 @@ When running any workflow:
for (const artifact of artifacts) {
if (artifact.type === 'workflow-command') {
// Convert relativePath to colon format: bmm/workflows/correct-course.md → bmad:bmm:correct-course.md
// Convert relativePath to underscore format: bmm/workflows/correct-course.md → bmad_bmm_correct-course.md
const flatName = toColonPath(artifact.relativePath);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));
@@ -265,8 +265,8 @@ When running any workflow:
}
/**
* Write workflow command artifacts using DASH format (for flat IDEs)
* Creates flat files like: bmad-bmm-correct-course.md
* Write workflow command artifacts using underscore format (Windows-compatible)
* Creates flat files like: bmad_bmm_correct-course.md
*
* @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Workflow artifacts
@@ -277,7 +277,7 @@ When running any workflow:
for (const artifact of artifacts) {
if (artifact.type === 'workflow-command') {
// Convert relativePath to dash format: bmm/workflows/correct-course.md → bmad-bmm-correct-course.md
// Convert relativePath to underscore format: bmm/workflows/correct-course.md → bmad_bmm_correct-course.md
const flatName = toDashPath(artifact.relativePath);
const commandPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(commandPath));

View File

@@ -246,12 +246,12 @@ Part of the BMAD ${workflow.module.toUpperCase()} module.
const rulesPath = path.join(projectDir, this.configDir, this.rulesDir);
if (await fs.pathExists(rulesPath)) {
// Only remove files that start with bmad- prefix
// Remove any bmad* files (cleans up old bmad- and bmad: formats)
const files = await fs.readdir(rulesPath);
let removed = 0;
for (const file of files) {
if (file.startsWith('bmad-') && file.endsWith('.md')) {
if (file.startsWith('bmad') && file.endsWith('.md')) {
await fs.remove(path.join(rulesPath, file));
removed++;
}