Compare commits

...

4 Commits

Author SHA1 Message Date
ZvoneO b08909ccf4
Merge c035b2f247 into 4ded43d707 2026-01-27 22:10:07 -08:00
Brian Madison 4ded43d707 fix paths in prd edit flow 2026-01-27 22:03:53 -08:00
Davor Racic 181aeac04a
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 <bmadcode@gmail.com>
2026-01-27 21:56:12 -08:00
Murat K Ozcan f7466c2530
feat: added tea module as an external module (#1430) 2026-01-27 17:29:34 -08:00
15 changed files with 118 additions and 65 deletions

View File

@ -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'
---

View File

@ -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

View File

@ -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'
---

View File

@ -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

View File

@ -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:

View File

@ -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<string>} 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'];
for (const ext of extensions) {
const templatePath = path.join(templateDir, templateBaseName + ext);
if (await fs.pathExists(templatePath)) {
return await fs.readFile(templatePath, 'utf8');
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`);
for (const ext of extensions) {
const fallbackPath = path.join(templateDir, `${fallbackTemplateType}${ext}`);
if (await fs.pathExists(fallbackPath)) {
return await fs.readFile(fallbackPath, 'utf8');
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);
}
/**

View File

@ -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/')) {

View File

@ -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

View File

@ -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}}
"""

View File

@ -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}}
"""

View File

@ -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}}
"""

View File

@ -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
"""

View File

@ -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}}
"""

View File

@ -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.
<agent-activation CRITICAL="TRUE">
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 <activation> section precisely
4. DISPLAY the welcome/greeting as instructed
5. PRESENT the numbered menu
6. WAIT for user input before proceeding
</agent-activation>

View File

@ -1,2 +0,0 @@
name = "{{name}}"
description = "{{description}}"