From f7466c25308d1f68423207cf1bdcda3e43827262 Mon Sep 17 00:00:00 2001 From: Murat K Ozcan <34237651+muratkeremozcan@users.noreply.github.com> Date: Tue, 27 Jan 2026 19:29:34 -0600 Subject: [PATCH 1/4] feat: added tea module as an external module (#1430) --- tools/cli/external-official-modules.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/cli/external-official-modules.yaml b/tools/cli/external-official-modules.yaml index c48f7175..436dc01d 100644 --- a/tools/cli/external-official-modules.yaml +++ b/tools/cli/external-official-modules.yaml @@ -32,6 +32,16 @@ modules: type: bmad-org npmPackage: bmad-game-dev-studio + bmad-method-test-architecture-enterprise: + url: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise + module-definition: src/module.yaml + code: tea + name: "Test Architect" + description: "Master Test Architect for quality strategy, test automation, and release gates" + defaultSelected: false + type: bmad-org + npmPackage: bmad-method-test-architecture-enterprise + # TODO: Enable once fixes applied: # whiteport-design-system: From 181aeac04a0c00452ae5a0444ec565fa8ea32500 Mon Sep 17 00:00:00 2001 From: Davor Racic Date: Wed, 28 Jan 2026 06:56:12 +0100 Subject: [PATCH 2/4] fix(ide): add support for Gemini CLI TOML format (#1431) * fix(ide): add support for Gemini CLI TOML format * fix(ide): Added normalization for config.extension, added .yml to the extension array --------- Co-authored-by: Brian --- .../cli/installers/lib/ide/_config-driven.js | 65 +++++++++++++------ .../lib/ide/shared/agent-command-generator.js | 4 +- .../ide/shared/workflow-command-generator.js | 14 +++- .../ide/templates/combined/gemini-agent.toml | 14 ++++ .../combined/gemini-workflow-yaml.toml | 16 +++++ .../templates/combined/gemini-workflow.toml | 14 ++++ .../ide/templates/gemini-agent-command.toml | 14 ---- .../ide/templates/gemini-task-command.toml | 12 ---- .../lib/ide/templates/split/gemini/body.md | 10 --- .../ide/templates/split/gemini/header.toml | 2 - 10 files changed, 104 insertions(+), 61 deletions(-) create mode 100644 tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml create mode 100644 tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml create mode 100644 tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml delete mode 100644 tools/cli/installers/lib/ide/templates/gemini-agent-command.toml delete mode 100644 tools/cli/installers/lib/ide/templates/gemini-task-command.toml delete mode 100644 tools/cli/installers/lib/ide/templates/split/gemini/body.md delete mode 100644 tools/cli/installers/lib/ide/templates/split/gemini/header.toml diff --git a/tools/cli/installers/lib/ide/_config-driven.js b/tools/cli/installers/lib/ide/_config-driven.js index 7d637faf..4ebd173e 100644 --- a/tools/cli/installers/lib/ide/_config-driven.js +++ b/tools/cli/installers/lib/ide/_config-driven.js @@ -132,12 +132,12 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup { */ async writeAgentArtifacts(targetPath, artifacts, templateType, config = {}) { // Try to load platform-specific template, fall back to default-agent - const template = await this.loadTemplate(templateType, 'agent', config, 'default-agent'); + const { content: template, extension } = await this.loadTemplate(templateType, 'agent', config, 'default-agent'); let count = 0; for (const artifact of artifacts) { const content = this.renderTemplate(template, artifact); - const filename = this.generateFilename(artifact, 'agent'); + const filename = this.generateFilename(artifact, 'agent', extension); const filePath = path.join(targetPath, filename); await this.writeFile(filePath, content); count++; @@ -167,9 +167,10 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup { // Fall back to default templates if specific ones don't exist const finalTemplateType = artifact.isYamlWorkflow ? 'default-workflow-yaml' : 'default-workflow'; - const template = await this.loadTemplate(workflowTemplateType, 'workflow', config, finalTemplateType); + // workflowTemplateType already contains full name (e.g., 'gemini-workflow-yaml'), so pass empty artifactType + const { content: template, extension } = await this.loadTemplate(workflowTemplateType, '', config, finalTemplateType); const content = this.renderTemplate(template, artifact); - const filename = this.generateFilename(artifact, 'workflow'); + const filename = this.generateFilename(artifact, 'workflow', extension); const filePath = path.join(targetPath, filename); await this.writeFile(filePath, content); count++; @@ -185,34 +186,47 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup { * @param {string} artifactType - Artifact type (agent, workflow, task, tool) * @param {Object} config - Installation configuration * @param {string} fallbackTemplateType - Fallback template type if requested template not found - * @returns {Promise} Template content + * @returns {Promise<{content: string, extension: string}>} Template content and extension */ async loadTemplate(templateType, artifactType, config = {}, fallbackTemplateType = null) { const { header_template, body_template } = config; // Check for separate header/body templates if (header_template || body_template) { - return await this.loadSplitTemplates(templateType, artifactType, header_template, body_template); + const content = await this.loadSplitTemplates(templateType, artifactType, header_template, body_template); + // Allow config to override extension, default to .md + const ext = config.extension || '.md'; + const normalizedExt = ext.startsWith('.') ? ext : `.${ext}`; + return { content, extension: normalizedExt }; } - // Load combined template - const templateName = `${templateType}-${artifactType}.md`; - const templatePath = path.join(__dirname, 'templates', 'combined', templateName); + // Load combined template - try multiple extensions + // If artifactType is empty, templateType already contains full name (e.g., 'gemini-workflow-yaml') + const templateBaseName = artifactType ? `${templateType}-${artifactType}` : templateType; + const templateDir = path.join(__dirname, 'templates', 'combined'); + const extensions = ['.md', '.toml', '.yaml', '.yml']; - if (await fs.pathExists(templatePath)) { - return await fs.readFile(templatePath, 'utf8'); + for (const ext of extensions) { + const templatePath = path.join(templateDir, templateBaseName + ext); + if (await fs.pathExists(templatePath)) { + const content = await fs.readFile(templatePath, 'utf8'); + return { content, extension: ext }; + } } // Fall back to default template (if provided) if (fallbackTemplateType) { - const fallbackPath = path.join(__dirname, 'templates', 'combined', `${fallbackTemplateType}.md`); - if (await fs.pathExists(fallbackPath)) { - return await fs.readFile(fallbackPath, 'utf8'); + for (const ext of extensions) { + const fallbackPath = path.join(templateDir, `${fallbackTemplateType}${ext}`); + if (await fs.pathExists(fallbackPath)) { + const content = await fs.readFile(fallbackPath, 'utf8'); + return { content, extension: ext }; + } } } // Ultimate fallback - minimal template - return this.getDefaultTemplate(artifactType); + return { content: this.getDefaultTemplate(artifactType), extension: '.md' }; } /** @@ -326,13 +340,26 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}} * Generate filename for artifact * @param {Object} artifact - Artifact data * @param {string} artifactType - Artifact type (agent, workflow, task, tool) + * @param {string} extension - File extension to use (e.g., '.md', '.toml') * @returns {string} Generated filename */ - generateFilename(artifact, artifactType) { + generateFilename(artifact, artifactType, extension = '.md') { const { toDashPath } = require('./shared/path-utils'); - // toDashPath already handles the .agent.md suffix for agents correctly - // No need to add it again here - return toDashPath(artifact.relativePath); + + // Reuse central logic to ensure consistent naming conventions + const standardName = toDashPath(artifact.relativePath); + + // Clean up potential double extensions from source files (e.g. .yaml.md -> .md) + const baseName = standardName.replace(/\.(yaml|yml)\.md$/, '.md'); + + // If using default markdown, preserve original behavior (keeps .agent.md suffix) + if (extension === '.md') { + return baseName; + } + + // For other extensions (e.g., .toml), remove .agent suffix as well + // Gemini doesn't support double-dot patterns like .agent.toml + return baseName.replace(/(\.agent)?(\.md|\.yaml|\.yml)$/, extension); } /** 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 084ed048..da8c1ef0 100644 --- a/tools/cli/installers/lib/ide/shared/agent-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/agent-command-generator.js @@ -32,7 +32,9 @@ class AgentCommandGenerator { // Use relativePath if available (for nested agents), otherwise just name with .md const agentPathInModule = agent.relativePath || `${agent.name}.md`; // Calculate the relative agent path (e.g., bmm/agents/pm.md) - let agentRelPath = agent.path; + let agentRelPath = agent.path || ''; + // Normalize path separators for cross-platform compatibility + agentRelPath = agentRelPath.replaceAll('\\', '/'); // Remove _bmad/ prefix if present to get relative path from project root // Handle both absolute paths (/path/to/_bmad/...) and relative paths (_bmad/...) if (agentRelPath.includes('_bmad/')) { 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 b3410b0f..42bad24a 100644 --- a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js @@ -68,7 +68,9 @@ class WorkflowCommandGenerator { for (const workflow of allWorkflows) { const commandContent = await this.generateCommandContent(workflow, bmadDir); // Calculate the relative workflow path (e.g., bmm/workflows/4-implementation/sprint-planning/workflow.yaml) - let workflowRelPath = workflow.path; + let workflowRelPath = workflow.path || ''; + // Normalize path separators for cross-platform compatibility + workflowRelPath = workflowRelPath.replaceAll('\\', '/'); // Remove _bmad/ prefix if present to get relative path from project root // Handle both absolute paths (/path/to/_bmad/...) and relative paths (_bmad/...) if (workflowRelPath.includes('_bmad/')) { @@ -76,9 +78,15 @@ class WorkflowCommandGenerator { if (parts.length > 1) { workflowRelPath = parts.slice(1).join('/'); } + } else if (workflowRelPath.includes('/src/')) { + // Normalize source paths (e.g. .../src/bmm/...) to relative module path (e.g. bmm/...) + const match = workflowRelPath.match(/\/src\/([^/]+)\/(.+)/); + if (match) { + workflowRelPath = `${match[1]}/${match[2]}`; + } } - // Determine if this is a YAML workflow - const isYamlWorkflow = workflow.path.endsWith('.yaml') || workflow.path.endsWith('.yml'); + // Determine if this is a YAML workflow (use normalized path which is guaranteed to be a string) + const isYamlWorkflow = workflowRelPath.endsWith('.yaml') || workflowRelPath.endsWith('.yml'); artifacts.push({ type: 'workflow-command', isYamlWorkflow: isYamlWorkflow, // For template selection diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml new file mode 100644 index 00000000..ae5f791c --- /dev/null +++ b/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml @@ -0,0 +1,14 @@ +description = "Activates the {{name}} agent from the BMad Method." +prompt = """ +CRITICAL: You are now the BMad '{{name}}' agent. + +PRE-FLIGHT CHECKLIST: +1. [ ] IMMEDIATE ACTION: Load and parse {project-root}/{{bmadFolderName}}/{{module}}/config.yaml - store ALL config values in memory for use throughout the session. +2. [ ] IMMEDIATE ACTION: Read and internalize the full agent definition at {project-root}/{{bmadFolderName}}/{{path}}. +3. [ ] CONFIRM: The user's name from config is {user_name}. + +Only after all checks are complete, greet the user by name and display the menu. +Acknowledge this checklist is complete in your first response. + +AGENT DEFINITION: {project-root}/{{bmadFolderName}}/{{path}} +""" diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml new file mode 100644 index 00000000..063ca0d0 --- /dev/null +++ b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml @@ -0,0 +1,16 @@ +description = """{{description}}""" +prompt = """ +Execute the BMAD '{{name}}' workflow. + +CRITICAL: This is a structured YAML workflow. Follow these steps precisely: + +1. LOAD the workflow definition from {project-root}/{{bmadFolderName}}/{{workflow_path}} +2. PARSE the YAML structure to understand: + - Workflow phases and steps + - Required inputs and outputs + - Dependencies between steps +3. EXECUTE each step in order +4. VALIDATE outputs before proceeding to next step + +WORKFLOW FILE: {project-root}/{{bmadFolderName}}/{{workflow_path}} +""" diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml new file mode 100644 index 00000000..52624106 --- /dev/null +++ b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml @@ -0,0 +1,14 @@ +description = """{{description}}""" +prompt = """ +Execute the BMAD '{{name}}' workflow. + +CRITICAL: You must load and follow the workflow definition exactly. + +WORKFLOW INSTRUCTIONS: +1. LOAD the workflow file from {project-root}/{{bmadFolderName}}/{{workflow_path}} +2. READ its entire contents +3. FOLLOW every step precisely as specified +4. DO NOT skip or modify any steps + +WORKFLOW FILE: {project-root}/{{bmadFolderName}}/{{workflow_path}} +""" diff --git a/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml b/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml deleted file mode 100644 index 2dc4c2c5..00000000 --- a/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml +++ /dev/null @@ -1,14 +0,0 @@ -description = "Activates the {{title}} agent from the BMad Method." -prompt = """ -CRITICAL: You are now the BMad '{{title}}' agent. - -PRE-FLIGHT CHECKLIST: -1. [ ] IMMEDIATE ACTION: Load and parse @{_bmad}/{{module}}/config.yaml - store ALL config values in memory for use throughout the session. -2. [ ] IMMEDIATE ACTION: Read and internalize the full agent definition at @{_bmad}/{{module}}/agents/{{name}}.md. -3. [ ] CONFIRM: The user's name from config is {user_name}. - -Only after all checks are complete, greet the user by name and display the menu. -Acknowledge this checklist is complete in your first response. - -AGENT DEFINITION: @{_bmad}/{{module}}/agents/{{name}}.md -""" diff --git a/tools/cli/installers/lib/ide/templates/gemini-task-command.toml b/tools/cli/installers/lib/ide/templates/gemini-task-command.toml deleted file mode 100644 index 2dbedaaa..00000000 --- a/tools/cli/installers/lib/ide/templates/gemini-task-command.toml +++ /dev/null @@ -1,12 +0,0 @@ -description = "Executes the {{taskName}} task from the BMad Method." -prompt = """ -Execute the following BMad Method task workflow: - -PRE-FLIGHT CHECKLIST: -1. [ ] IMMEDIATE ACTION: Load and parse @{_bmad}/{{module}}/config.yaml. -2. [ ] IMMEDIATE ACTION: Read and load the task definition at @{_bmad}/{{module}}/tasks/{{filename}}. - -Follow all instructions and complete the task as defined. - -TASK DEFINITION: @{_bmad}/{{module}}/tasks/{{filename}} -""" diff --git a/tools/cli/installers/lib/ide/templates/split/gemini/body.md b/tools/cli/installers/lib/ide/templates/split/gemini/body.md deleted file mode 100644 index b20f6651..00000000 --- a/tools/cli/installers/lib/ide/templates/split/gemini/body.md +++ /dev/null @@ -1,10 +0,0 @@ -You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command. - - -1. LOAD the FULL agent file from {project-root}/_bmad/{{path}} -2. READ its entire contents - this contains the complete agent persona, menu, and instructions -3. FOLLOW every step in the section precisely -4. DISPLAY the welcome/greeting as instructed -5. PRESENT the numbered menu -6. WAIT for user input before proceeding - diff --git a/tools/cli/installers/lib/ide/templates/split/gemini/header.toml b/tools/cli/installers/lib/ide/templates/split/gemini/header.toml deleted file mode 100644 index 099b1e26..00000000 --- a/tools/cli/installers/lib/ide/templates/split/gemini/header.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "{{name}}" -description = "{{description}}" From 4ded43d707cde4efb918758e37f93ef7d16c0111 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Tue, 27 Jan 2026 22:03:37 -0800 Subject: [PATCH 3/4] fix paths in prd edit flow --- .../2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md | 2 +- .../create-prd/steps-e/step-e-01b-legacy-conversion.md | 2 +- .../2-plan-workflows/create-prd/steps-e/step-e-02-review.md | 2 +- .../2-plan-workflows/create-prd/steps-e/step-e-03-edit.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md index 7af674fd..8f47cd55 100644 --- a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +++ b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md @@ -4,7 +4,7 @@ description: 'Discovery & Understanding - Understand what user wants to edit and # File references (ONLY variables used in this step) altStepFile: './step-e-01b-legacy-conversion.md' -prdPurpose: '{project-root}/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '{project-root}/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' advancedElicitationTask: '{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.xml' partyModeWorkflow: '{project-root}/_bmad/core/workflows/party-mode/workflow.md' --- diff --git a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md index 5be8f63a..d13531d2 100644 --- a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +++ b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md @@ -5,7 +5,7 @@ description: 'Legacy PRD Conversion Assessment - Analyze legacy PRD and propose # File references (ONLY variables used in this step) nextStepFile: './step-e-02-review.md' prdFile: '{prd_file_path}' -prdPurpose: '{project-root}/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '{project-root}/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' --- # Step E-1B: Legacy PRD Conversion Assessment diff --git a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md index e89c1500..f34de79f 100644 --- a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +++ b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md @@ -6,7 +6,7 @@ description: 'Deep Review & Analysis - Thoroughly review existing PRD and prepar nextStepFile: './step-e-03-edit.md' prdFile: '{prd_file_path}' validationReport: '{validation_report_path}' # If provided -prdPurpose: '{project-root}/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '{project-root}/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' advancedElicitationTask: '{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.xml' --- diff --git a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md index c60a1d5e..65c12946 100644 --- a/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +++ b/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md @@ -5,7 +5,7 @@ description: 'Edit & Update - Apply changes to PRD following approved change pla # File references (ONLY variables used in this step) nextStepFile: './step-e-04-complete.md' prdFile: '{prd_file_path}' -prdPurpose: '{project-root}/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '{project-root}/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md' --- # Step E-3: Edit & Update From dd8c54cc9f6075d501c47394e45479deb67dd301 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Tue, 27 Jan 2026 23:08:26 -0800 Subject: [PATCH 4/4] no double agent files and .agent.md file extensions. --- .../cli/installers/lib/ide/_config-driven.js | 8 +- .../installers/lib/ide/platform-codes.yaml | 172 ++++++++---------- .../lib/ide/shared/agent-command-generator.js | 6 +- .../installers/lib/ide/shared/path-utils.js | 65 ++++--- .../ide/shared/task-tool-command-generator.js | 2 +- .../ide/shared/workflow-command-generator.js | 2 +- 6 files changed, 126 insertions(+), 129 deletions(-) diff --git a/tools/cli/installers/lib/ide/_config-driven.js b/tools/cli/installers/lib/ide/_config-driven.js index 4ebd173e..022bff7b 100644 --- a/tools/cli/installers/lib/ide/_config-driven.js +++ b/tools/cli/installers/lib/ide/_config-driven.js @@ -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) const baseName = standardName.replace(/\.(yaml|yml)\.md$/, '.md'); - // If using default markdown, preserve original behavior (keeps .agent.md suffix) + // If using default markdown, preserve the bmad-agent- prefix for agents if (extension === '.md') { return baseName; } - // For other extensions (e.g., .toml), remove .agent suffix as well - // Gemini doesn't support double-dot patterns like .agent.toml - return baseName.replace(/(\.agent)?(\.md|\.yaml|\.yml)$/, extension); + // For other extensions (e.g., .toml), replace .md extension + // Note: agent prefix is preserved even with non-markdown extensions + return baseName.replace(/\.md$/, extension); } /** diff --git a/tools/cli/installers/lib/ide/platform-codes.yaml b/tools/cli/installers/lib/ide/platform-codes.yaml index e3aea054..6a9078a8 100644 --- a/tools/cli/installers/lib/ide/platform-codes.yaml +++ b/tools/cli/installers/lib/ide/platform-codes.yaml @@ -14,18 +14,14 @@ # installer: Installation configuration (optional - omit for custom installers) platforms: - # ============================================================================ - # CLI Tools - # ============================================================================ - - claude-code: - name: "Claude Code" - preferred: true - category: cli - description: "Anthropic's official CLI for Claude" + antigravity: + name: "Google Antigravity" + preferred: false + category: ide + description: "Google's AI development environment" installer: - target_dir: .claude/commands - template_type: default + target_dir: .agent/workflows + template_type: antigravity auggie: name: "Auggie" @@ -36,37 +32,15 @@ platforms: target_dir: .augment/commands template_type: default - gemini: - name: "Gemini CLI" - preferred: false + claude-code: + name: "Claude Code" + preferred: true category: cli - description: "Google's CLI for Gemini" + description: "Anthropic's official CLI for Claude" installer: - target_dir: .gemini/commands - template_type: gemini - - # ============================================================================ - # IDEs - # ============================================================================ - - cursor: - name: "Cursor" - preferred: true - category: ide - description: "AI-first code editor" - installer: - target_dir: .cursor/commands + target_dir: .claude/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 @@ -76,15 +50,40 @@ platforms: target_dir: .clinerules/workflows template_type: windsurf - roo: - name: "Roo Cline" + codex: + name: "Codex" + preferred: false + category: cli + description: "OpenAI Codex integration" + # No installer config - uses custom codex.js + + crush: + name: "Crush" preferred: false category: ide - description: "Enhanced Cline fork" + description: "AI development assistant" installer: - target_dir: .roo/commands + target_dir: .crush/commands template_type: default + cursor: + name: "Cursor" + preferred: true + category: ide + description: "AI-first code editor" + installer: + target_dir: .cursor/commands + template_type: default + + gemini: + name: "Gemini CLI" + preferred: false + category: cli + description: "Google's CLI for Gemini" + installer: + target_dir: .gemini/commands + template_type: gemini + github-copilot: name: "GitHub Copilot" preferred: false @@ -99,24 +98,6 @@ platforms: template_type: vscode_settings artifact_types: [] - opencode: - name: "OpenCode" - preferred: false - category: ide - description: "OpenCode terminal coding assistant" - installer: - target_dir: .opencode/command - 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 @@ -126,6 +107,29 @@ platforms: 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: + name: "OpenCode" + preferred: false + category: ide + description: "OpenCode terminal coding assistant" + installer: + target_dir: .opencode/command + template_type: opencode + qwen: name: "QwenCoder" preferred: false @@ -135,6 +139,15 @@ platforms: target_dir: .qwen/commands 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: name: "Rovo Dev" preferred: false @@ -153,41 +166,14 @@ platforms: target_dir: .trae/rules template_type: trae - antigravity: - name: "Google Antigravity" - preferred: false + windsurf: + name: "Windsurf" + preferred: true category: ide - description: "Google's AI development environment" + description: "AI-powered IDE with cascade flows" installer: - target_dir: .agent/workflows - 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) + target_dir: .windsurf/workflows + template_type: windsurf # ============================================================================ # Installer Config Schema 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 da8c1ef0..dec22a12 100644 --- a/tools/cli/installers/lib/ide/shared/agent-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/agent-command-generator.js @@ -134,9 +134,9 @@ class AgentCommandGenerator { /** * Write agent launcher artifacts using dash format (NEW STANDARD) - * Creates flat files like: bmad-bmm-pm.agent.md + * Creates flat files like: bmad-agent-bmm-pm.md * - * The .agent.md suffix distinguishes agents from workflows/tasks/tools. + * The bmad-agent- prefix distinguishes agents from workflows/tasks/tools. * * @param {string} baseCommandsDir - Base commands directory for the IDE * @param {Array} artifacts - Agent launcher artifacts @@ -147,7 +147,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.agent.md + // Convert relativePath to dash format: bmm/agents/pm.md → bmad-agent-bmm-pm.md const flatName = toDashPath(artifact.relativePath); const launcherPath = path.join(baseCommandsDir, flatName); await fs.ensureDir(path.dirname(launcherPath)); diff --git a/tools/cli/installers/lib/ide/shared/path-utils.js b/tools/cli/installers/lib/ide/shared/path-utils.js index 7c335d4b..d6ad00f5 100644 --- a/tools/cli/installers/lib/ide/shared/path-utils.js +++ b/tools/cli/installers/lib/ide/shared/path-utils.js @@ -4,14 +4,14 @@ * Provides utilities to convert hierarchical paths to flat naming conventions. * * DASH-BASED NAMING (new standard): - * - Agents: bmad-module-name.agent.md (with .agent.md suffix) + * - Agents: bmad-agent-module-name.md (with bmad-agent- prefix) * - Workflows/Tasks/Tools: bmad-module-name.md * * Example outputs: - * - cis/agents/storymaster.md → bmad-cis-storymaster.agent.md + * - cis/agents/storymaster.md → bmad-agent-cis-storymaster.md * - bmm/workflows/plan-project.md → bmad-bmm-plan-project.md * - bmm/tasks/create-story.md → bmad-bmm-create-story.md - * - core/agents/brainstorming.md → bmad-brainstorming.agent.md + * - core/agents/brainstorming.md → bmad-agent-brainstorming.md (core agents skip module name) */ // Type segments - agents are included in naming, others are filtered out @@ -20,37 +20,38 @@ const AGENT_SEGMENT = 'agents'; /** * Convert hierarchical path to flat dash-separated name (NEW STANDARD) - * Converts: 'bmm', 'agents', 'pm' → 'bmad-bmm-pm.agent.md' + * Converts: 'bmm', 'agents', 'pm' → 'bmad-agent-bmm-pm.md' * Converts: 'bmm', 'workflows', 'correct-course' → 'bmad-bmm-correct-course.md' - * Converts: 'core', 'agents', 'brainstorming' → 'bmad-brainstorming.agent.md' (core items skip module prefix) + * Converts: 'core', 'agents', 'brainstorming' → 'bmad-agent-brainstorming.md' (core agents skip module name) * * @param {string} module - Module name (e.g., 'bmm', 'core') * @param {string} type - Artifact type ('agents', 'workflows', 'tasks', 'tools') * @param {string} name - Artifact name (e.g., 'pm', 'brainstorming') - * @returns {string} Flat filename like 'bmad-bmm-pm.agent.md' or 'bmad-bmm-correct-course.md' + * @returns {string} Flat filename like 'bmad-agent-bmm-pm.md' or 'bmad-bmm-correct-course.md' */ function toDashName(module, type, name) { const isAgent = type === AGENT_SEGMENT; - // For core module, skip the module prefix: use 'bmad-name.md' instead of 'bmad-core-name.md' + // For core module, skip the module name: use 'bmad-agent-name.md' instead of 'bmad-agent-core-name.md' if (module === 'core') { - return isAgent ? `bmad-${name}.agent.md` : `bmad-${name}.md`; + return isAgent ? `bmad-agent-${name}.md` : `bmad-${name}.md`; } - // Module artifacts: bmad-module-name.md or bmad-module-name.agent.md + // Module artifacts: bmad-module-name.md or bmad-agent-module-name.md // eslint-disable-next-line unicorn/prefer-string-replace-all -- regex replace is intentional here const dashName = name.replace(/\//g, '-'); // Flatten nested paths - return isAgent ? `bmad-${module}-${dashName}.agent.md` : `bmad-${module}-${dashName}.md`; + return isAgent ? `bmad-agent-${module}-${dashName}.md` : `bmad-${module}-${dashName}.md`; } /** * Convert relative path to flat dash-separated name - * Converts: 'bmm/agents/pm.md' → 'bmad-bmm-pm.agent.md' + * Converts: 'bmm/agents/pm.md' → 'bmad-agent-bmm-pm.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: 'core/agents/brainstorming.md' → 'bmad-brainstorming.agent.md' (core items skip module prefix) + * Converts: 'core/agents/brainstorming.md' → 'bmad-agent-brainstorming.md' (core agents skip module name) * * @param {string} relativePath - Path like 'bmm/agents/pm.md' - * @returns {string} Flat filename like 'bmad-bmm-pm.agent.md' or 'bmad-brainstorming.md' + * @returns {string} Flat filename like 'bmad-agent-bmm-pm.md' or 'bmad-brainstorming.md' */ function toDashPath(relativePath) { if (!relativePath || typeof relativePath !== 'string') { @@ -63,20 +64,30 @@ function toDashPath(relativePath) { const module = parts[0]; const type = parts[1]; - const name = parts.slice(2).join('-'); + let name; + + // 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); } /** * Create custom agent dash name - * Creates: 'bmad-custom-fred-commit-poet.agent.md' + * Creates: 'bmad-custom-agent-fred-commit-poet.md' * * @param {string} agentName - Custom agent name - * @returns {string} Flat filename like 'bmad-custom-fred-commit-poet.agent.md' + * @returns {string} Flat filename like 'bmad-custom-agent-fred-commit-poet.md' */ function customAgentDashName(agentName) { - return `bmad-custom-${agentName}.agent.md`; + return `bmad-custom-agent-${agentName}.md`; } /** @@ -90,9 +101,9 @@ function isDashFormat(filename) { /** * Extract parts from a dash-formatted filename - * Parses: 'bmad-bmm-pm.agent.md' → { prefix: 'bmad', module: 'bmm', type: 'agents', name: 'pm' } + * Parses: 'bmad-agent-bmm-pm.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-brainstorming.agent.md' → { prefix: 'bmad', module: 'core', type: 'agents', name: 'brainstorming' } (core agents) + * Parses: 'bmad-agent-brainstorming.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) * * @param {string} filename - Dash-formatted filename @@ -106,27 +117,27 @@ function parseDashName(filename) { return null; } - // Check if this is an agent file (has .agent suffix) - const isAgent = withoutExt.endsWith('.agent'); + // Check if this is an agent file (has 'agent' as second part) + const isAgent = parts[1] === 'agent'; if (isAgent) { // This is an agent file - // Format: bmad-name.agent (core) or bmad-module-name.agent + // Format: bmad-agent-name (core) or bmad-agent-module-name if (parts.length === 3) { - // Core agent: bmad-name.agent + // Core agent: bmad-agent-name return { prefix: parts[0], module: 'core', type: 'agents', - name: parts[1], + name: parts[2], }; } else { - // Module agent: bmad-module-name.agent + // Module agent: bmad-agent-module-name return { prefix: parts[0], - module: parts[1], + module: parts[2], type: 'agents', - name: parts.slice(2).join('-'), + name: parts.slice(3).join('-'), }; } } 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 0e54ad89..6b90de9f 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 @@ -242,7 +242,7 @@ Follow all instructions in the ${type} file exactly as written. * Write task/tool artifacts using dash format (NEW STANDARD) * Creates flat files like: bmad-bmm-bmad-help.md * - * Note: Tasks/tools do NOT have .agent.md suffix - only agents do. + * Note: Tasks/tools do NOT have bmad-agent- prefix - only agents do. * * @param {string} baseCommandsDir - Base commands directory for the IDE * @param {Array} artifacts - Task/tool artifacts with relativePath 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 42bad24a..6dab1a3f 100644 --- a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js @@ -292,7 +292,7 @@ When running any workflow: * Write workflow command artifacts using dash format (NEW STANDARD) * Creates flat files like: bmad-bmm-correct-course.md * - * Note: Workflows do NOT have .agent.md suffix - only agents do. + * Note: Workflows do NOT have bmad-agent- prefix - only agents do. * * @param {string} baseCommandsDir - Base commands directory for the IDE * @param {Array} artifacts - Workflow artifacts