Compare commits

..

1 Commits

Author SHA1 Message Date
Michael Pursifull 1cfcad60a3
Merge 99aaa42359 into 4ded43d707 2026-01-28 00:19:25 -06:00
6 changed files with 134 additions and 131 deletions

View File

@ -352,14 +352,14 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
// Clean up potential double extensions from source files (e.g. .yaml.md -> .md) // Clean up potential double extensions from source files (e.g. .yaml.md -> .md)
const baseName = standardName.replace(/\.(yaml|yml)\.md$/, '.md'); const baseName = standardName.replace(/\.(yaml|yml)\.md$/, '.md');
// If using default markdown, preserve the bmad-agent- prefix for agents // If using default markdown, preserve original behavior (keeps .agent.md suffix)
if (extension === '.md') { if (extension === '.md') {
return baseName; return baseName;
} }
// For other extensions (e.g., .toml), replace .md extension // For other extensions (e.g., .toml), remove .agent suffix as well
// Note: agent prefix is preserved even with non-markdown extensions // Gemini doesn't support double-dot patterns like .agent.toml
return baseName.replace(/\.md$/, extension); return baseName.replace(/(\.agent)?(\.md|\.yaml|\.yml)$/, extension);
} }
/** /**

View File

@ -14,23 +14,9 @@
# installer: Installation configuration (optional - omit for custom installers) # installer: Installation configuration (optional - omit for custom installers)
platforms: platforms:
antigravity: # ============================================================================
name: "Google Antigravity" # CLI Tools
preferred: false # ============================================================================
category: ide
description: "Google's AI development environment"
installer:
target_dir: .agent/workflows
template_type: antigravity
auggie:
name: "Auggie"
preferred: false
category: cli
description: "AI development tool"
installer:
target_dir: .augment/commands
template_type: default
claude-code: claude-code:
name: "Claude Code" name: "Claude Code"
@ -41,38 +27,13 @@ platforms:
target_dir: .claude/commands target_dir: .claude/commands
template_type: default template_type: default
cline: auggie:
name: "Cline" name: "Auggie"
preferred: false
category: ide
description: "AI coding assistant"
installer:
target_dir: .clinerules/workflows
template_type: windsurf
codex:
name: "Codex"
preferred: false preferred: false
category: cli category: cli
description: "OpenAI Codex integration" description: "AI development tool"
# No installer config - uses custom codex.js
crush:
name: "Crush"
preferred: false
category: ide
description: "AI development assistant"
installer: installer:
target_dir: .crush/commands target_dir: .augment/commands
template_type: default
cursor:
name: "Cursor"
preferred: true
category: ide
description: "AI-first code editor"
installer:
target_dir: .cursor/commands
template_type: default template_type: default
gemini: gemini:
@ -84,6 +45,46 @@ platforms:
target_dir: .gemini/commands target_dir: .gemini/commands
template_type: gemini template_type: gemini
# ============================================================================
# IDEs
# ============================================================================
cursor:
name: "Cursor"
preferred: true
category: ide
description: "AI-first code editor"
installer:
target_dir: .cursor/commands
template_type: default
windsurf:
name: "Windsurf"
preferred: true
category: ide
description: "AI-powered IDE with cascade flows"
installer:
target_dir: .windsurf/workflows
template_type: windsurf
cline:
name: "Cline"
preferred: false
category: ide
description: "AI coding assistant"
installer:
target_dir: .clinerules/workflows
template_type: windsurf
roo:
name: "Roo Cline"
preferred: false
category: ide
description: "Enhanced Cline fork"
installer:
target_dir: .roo/commands
template_type: default
github-copilot: github-copilot:
name: "GitHub Copilot" name: "GitHub Copilot"
preferred: false preferred: false
@ -98,29 +99,6 @@ platforms:
template_type: vscode_settings template_type: vscode_settings
artifact_types: [] artifact_types: []
iflow:
name: "iFlow"
preferred: false
category: ide
description: "AI workflow automation"
installer:
target_dir: .iflow/commands
template_type: default
kilo:
name: "KiloCoder"
preferred: false
category: ide
description: "AI coding platform"
# No installer config - uses custom kilo.js (creates .kilocodemodes file)
kiro-cli:
name: "Kiro CLI"
preferred: false
category: cli
description: "Kiro command-line interface"
# No installer config - uses custom kiro-cli.js (YAML→JSON conversion)
opencode: opencode:
name: "OpenCode" name: "OpenCode"
preferred: false preferred: false
@ -130,6 +108,24 @@ platforms:
target_dir: .opencode/command target_dir: .opencode/command
template_type: opencode template_type: opencode
crush:
name: "Crush"
preferred: false
category: ide
description: "AI development assistant"
installer:
target_dir: .crush/commands
template_type: default
iflow:
name: "iFlow"
preferred: false
category: ide
description: "AI workflow automation"
installer:
target_dir: .iflow/commands
template_type: default
qwen: qwen:
name: "QwenCoder" name: "QwenCoder"
preferred: false preferred: false
@ -139,15 +135,6 @@ platforms:
target_dir: .qwen/commands target_dir: .qwen/commands
template_type: default template_type: default
roo:
name: "Roo Cline"
preferred: false
category: ide
description: "Enhanced Cline fork"
installer:
target_dir: .roo/commands
template_type: default
rovo-dev: rovo-dev:
name: "Rovo Dev" name: "Rovo Dev"
preferred: false preferred: false
@ -166,14 +153,41 @@ platforms:
target_dir: .trae/rules target_dir: .trae/rules
template_type: trae template_type: trae
windsurf: antigravity:
name: "Windsurf" name: "Google Antigravity"
preferred: true preferred: false
category: ide category: ide
description: "AI-powered IDE with cascade flows" description: "Google's AI development environment"
installer: installer:
target_dir: .windsurf/workflows target_dir: .agent/workflows
template_type: windsurf template_type: antigravity
# Note: Antigravity uses .agent/workflows/ directory (not .antigravity/)
# ============================================================================
# Custom Installers (no installer config - use custom file)
# These have unique installation logic that doesn't fit the config-driven model
# ============================================================================
codex:
name: "Codex"
preferred: false
category: cli
description: "OpenAI Codex integration"
# No installer config - uses custom codex.js
kilo:
name: "KiloCoder"
preferred: false
category: ide
description: "AI coding platform"
# No installer config - uses custom kilo.js (creates .kilocodemodes file)
kiro-cli:
name: "Kiro CLI"
preferred: false
category: cli
description: "Kiro command-line interface"
# No installer config - uses custom kiro-cli.js (YAML→JSON conversion)
# ============================================================================ # ============================================================================
# Installer Config Schema # Installer Config Schema

View File

@ -134,9 +134,9 @@ class AgentCommandGenerator {
/** /**
* Write agent launcher artifacts using dash format (NEW STANDARD) * Write agent launcher artifacts using dash format (NEW STANDARD)
* Creates flat files like: bmad-agent-bmm-pm.md * Creates flat files like: bmad-bmm-pm.agent.md
* *
* The bmad-agent- prefix distinguishes agents from workflows/tasks/tools. * The .agent.md suffix distinguishes agents from workflows/tasks/tools.
* *
* @param {string} baseCommandsDir - Base commands directory for the IDE * @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Agent launcher artifacts * @param {Array} artifacts - Agent launcher artifacts
@ -147,7 +147,7 @@ class AgentCommandGenerator {
for (const artifact of artifacts) { for (const artifact of artifacts) {
if (artifact.type === 'agent-launcher') { if (artifact.type === 'agent-launcher') {
// Convert relativePath to dash format: bmm/agents/pm.md → bmad-agent-bmm-pm.md // Convert relativePath to dash format: bmm/agents/pm.md → bmad-bmm-pm.agent.md
const flatName = toDashPath(artifact.relativePath); const flatName = toDashPath(artifact.relativePath);
const launcherPath = path.join(baseCommandsDir, flatName); const launcherPath = path.join(baseCommandsDir, flatName);
await fs.ensureDir(path.dirname(launcherPath)); await fs.ensureDir(path.dirname(launcherPath));

View File

@ -4,14 +4,14 @@
* Provides utilities to convert hierarchical paths to flat naming conventions. * Provides utilities to convert hierarchical paths to flat naming conventions.
* *
* DASH-BASED NAMING (new standard): * DASH-BASED NAMING (new standard):
* - Agents: bmad-agent-module-name.md (with bmad-agent- prefix) * - Agents: bmad-module-name.agent.md (with .agent.md suffix)
* - Workflows/Tasks/Tools: bmad-module-name.md * - Workflows/Tasks/Tools: bmad-module-name.md
* *
* Example outputs: * Example outputs:
* - cis/agents/storymaster.md bmad-agent-cis-storymaster.md * - cis/agents/storymaster.md bmad-cis-storymaster.agent.md
* - bmm/workflows/plan-project.md bmad-bmm-plan-project.md * - bmm/workflows/plan-project.md bmad-bmm-plan-project.md
* - bmm/tasks/create-story.md bmad-bmm-create-story.md * - bmm/tasks/create-story.md bmad-bmm-create-story.md
* - core/agents/brainstorming.md bmad-agent-brainstorming.md (core agents skip module name) * - core/agents/brainstorming.md bmad-brainstorming.agent.md
*/ */
// Type segments - agents are included in naming, others are filtered out // Type segments - agents are included in naming, others are filtered out
@ -20,38 +20,37 @@ const AGENT_SEGMENT = 'agents';
/** /**
* Convert hierarchical path to flat dash-separated name (NEW STANDARD) * Convert hierarchical path to flat dash-separated name (NEW STANDARD)
* Converts: 'bmm', 'agents', 'pm' 'bmad-agent-bmm-pm.md' * Converts: 'bmm', 'agents', 'pm' 'bmad-bmm-pm.agent.md'
* Converts: 'bmm', 'workflows', 'correct-course' 'bmad-bmm-correct-course.md' * Converts: 'bmm', 'workflows', 'correct-course' 'bmad-bmm-correct-course.md'
* Converts: 'core', 'agents', 'brainstorming' 'bmad-agent-brainstorming.md' (core agents skip module name) * Converts: 'core', 'agents', 'brainstorming' 'bmad-brainstorming.agent.md' (core items skip module prefix)
* *
* @param {string} module - Module name (e.g., 'bmm', 'core') * @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')
* @param {string} name - Artifact name (e.g., 'pm', 'brainstorming') * @param {string} name - Artifact name (e.g., 'pm', 'brainstorming')
* @returns {string} Flat filename like 'bmad-agent-bmm-pm.md' or 'bmad-bmm-correct-course.md' * @returns {string} Flat filename like 'bmad-bmm-pm.agent.md' or 'bmad-bmm-correct-course.md'
*/ */
function toDashName(module, type, name) { function toDashName(module, type, name) {
const isAgent = type === AGENT_SEGMENT; const isAgent = type === AGENT_SEGMENT;
// For core module, skip the module name: use 'bmad-agent-name.md' instead of 'bmad-agent-core-name.md' // For core module, skip the module prefix: use 'bmad-name.md' instead of 'bmad-core-name.md'
if (module === 'core') { if (module === 'core') {
return isAgent ? `bmad-agent-${name}.md` : `bmad-${name}.md`; return isAgent ? `bmad-${name}.agent.md` : `bmad-${name}.md`;
} }
// Module artifacts: bmad-module-name.md or bmad-agent-module-name.md // Module artifacts: bmad-module-name.md or bmad-module-name.agent.md
// eslint-disable-next-line unicorn/prefer-string-replace-all -- regex replace is intentional here // eslint-disable-next-line unicorn/prefer-string-replace-all -- regex replace is intentional here
const dashName = name.replace(/\//g, '-'); // Flatten nested paths const dashName = name.replace(/\//g, '-'); // Flatten nested paths
return isAgent ? `bmad-agent-${module}-${dashName}.md` : `bmad-${module}-${dashName}.md`; return isAgent ? `bmad-${module}-${dashName}.agent.md` : `bmad-${module}-${dashName}.md`;
} }
/** /**
* Convert relative path to flat dash-separated name * Convert relative path to flat dash-separated name
* Converts: 'bmm/agents/pm.md' 'bmad-agent-bmm-pm.md' * Converts: 'bmm/agents/pm.md' 'bmad-bmm-pm.agent.md'
* Converts: 'bmm/agents/tech-writer/tech-writer.md' 'bmad-agent-bmm-tech-writer.md' (uses folder name)
* Converts: 'bmm/workflows/correct-course.md' 'bmad-bmm-correct-course.md' * Converts: 'bmm/workflows/correct-course.md' 'bmad-bmm-correct-course.md'
* Converts: 'core/agents/brainstorming.md' 'bmad-agent-brainstorming.md' (core agents skip module name) * Converts: 'core/agents/brainstorming.md' 'bmad-brainstorming.agent.md' (core items skip module prefix)
* *
* @param {string} relativePath - Path like 'bmm/agents/pm.md' * @param {string} relativePath - Path like 'bmm/agents/pm.md'
* @returns {string} Flat filename like 'bmad-agent-bmm-pm.md' or 'bmad-brainstorming.md' * @returns {string} Flat filename like 'bmad-bmm-pm.agent.md' or 'bmad-brainstorming.md'
*/ */
function toDashPath(relativePath) { function toDashPath(relativePath) {
if (!relativePath || typeof relativePath !== 'string') { if (!relativePath || typeof relativePath !== 'string') {
@ -64,30 +63,20 @@ function toDashPath(relativePath) {
const module = parts[0]; const module = parts[0];
const type = parts[1]; const type = parts[1];
let name; const name = parts.slice(2).join('-');
// For agents, if nested in a folder (more than 3 parts), use the folder name only
// e.g., 'bmm/agents/tech-writer/tech-writer' → 'tech-writer' (not 'tech-writer-tech-writer')
if (type === 'agents' && parts.length > 3) {
// Use the folder name (parts[2]) as the name, ignore the file name
name = parts[2];
} else {
// For non-nested or non-agents, join all parts after type
name = parts.slice(2).join('-');
}
return toDashName(module, type, name); return toDashName(module, type, name);
} }
/** /**
* Create custom agent dash name * Create custom agent dash name
* Creates: 'bmad-custom-agent-fred-commit-poet.md' * Creates: 'bmad-custom-fred-commit-poet.agent.md'
* *
* @param {string} agentName - Custom agent name * @param {string} agentName - Custom agent name
* @returns {string} Flat filename like 'bmad-custom-agent-fred-commit-poet.md' * @returns {string} Flat filename like 'bmad-custom-fred-commit-poet.agent.md'
*/ */
function customAgentDashName(agentName) { function customAgentDashName(agentName) {
return `bmad-custom-agent-${agentName}.md`; return `bmad-custom-${agentName}.agent.md`;
} }
/** /**
@ -101,9 +90,9 @@ function isDashFormat(filename) {
/** /**
* Extract parts from a dash-formatted filename * Extract parts from a dash-formatted filename
* Parses: 'bmad-agent-bmm-pm.md' { prefix: 'bmad', module: 'bmm', type: 'agents', name: 'pm' } * Parses: 'bmad-bmm-pm.agent.md' { prefix: 'bmad', module: 'bmm', type: 'agents', name: 'pm' }
* Parses: 'bmad-bmm-correct-course.md' { prefix: 'bmad', module: 'bmm', type: 'workflows', name: 'correct-course' } * Parses: 'bmad-bmm-correct-course.md' { prefix: 'bmad', module: 'bmm', type: 'workflows', name: 'correct-course' }
* Parses: 'bmad-agent-brainstorming.md' { prefix: 'bmad', module: 'core', type: 'agents', name: 'brainstorming' } (core agents) * Parses: 'bmad-brainstorming.agent.md' { prefix: 'bmad', module: 'core', type: 'agents', name: 'brainstorming' } (core agents)
* Parses: 'bmad-brainstorming.md' { prefix: 'bmad', module: 'core', type: 'workflows', name: 'brainstorming' } (core workflows) * Parses: 'bmad-brainstorming.md' { prefix: 'bmad', module: 'core', type: 'workflows', name: 'brainstorming' } (core workflows)
* *
* @param {string} filename - Dash-formatted filename * @param {string} filename - Dash-formatted filename
@ -117,27 +106,27 @@ function parseDashName(filename) {
return null; return null;
} }
// Check if this is an agent file (has 'agent' as second part) // Check if this is an agent file (has .agent suffix)
const isAgent = parts[1] === 'agent'; const isAgent = withoutExt.endsWith('.agent');
if (isAgent) { if (isAgent) {
// This is an agent file // This is an agent file
// Format: bmad-agent-name (core) or bmad-agent-module-name // Format: bmad-name.agent (core) or bmad-module-name.agent
if (parts.length === 3) { if (parts.length === 3) {
// Core agent: bmad-agent-name // Core agent: bmad-name.agent
return { return {
prefix: parts[0], prefix: parts[0],
module: 'core', module: 'core',
type: 'agents', type: 'agents',
name: parts[2], name: parts[1],
}; };
} else { } else {
// Module agent: bmad-agent-module-name // Module agent: bmad-module-name.agent
return { return {
prefix: parts[0], prefix: parts[0],
module: parts[2], module: parts[1],
type: 'agents', type: 'agents',
name: parts.slice(3).join('-'), name: parts.slice(2).join('-'),
}; };
} }
} }

View File

@ -242,7 +242,7 @@ Follow all instructions in the ${type} file exactly as written.
* Write task/tool artifacts using dash format (NEW STANDARD) * Write task/tool artifacts using dash format (NEW STANDARD)
* Creates flat files like: bmad-bmm-bmad-help.md * Creates flat files like: bmad-bmm-bmad-help.md
* *
* Note: Tasks/tools do NOT have bmad-agent- prefix - only agents do. * Note: Tasks/tools do NOT have .agent.md suffix - only agents do.
* *
* @param {string} baseCommandsDir - Base commands directory for the IDE * @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Task/tool artifacts with relativePath * @param {Array} artifacts - Task/tool artifacts with relativePath

View File

@ -292,7 +292,7 @@ When running any workflow:
* Write workflow command artifacts using dash format (NEW STANDARD) * Write workflow command artifacts using dash format (NEW STANDARD)
* Creates flat files like: bmad-bmm-correct-course.md * Creates flat files like: bmad-bmm-correct-course.md
* *
* Note: Workflows do NOT have bmad-agent- prefix - only agents do. * Note: Workflows do NOT have .agent.md suffix - only agents do.
* *
* @param {string} baseCommandsDir - Base commands directory for the IDE * @param {string} baseCommandsDir - Base commands directory for the IDE
* @param {Array} artifacts - Workflow artifacts * @param {Array} artifacts - Workflow artifacts