formatter updates
This commit is contained in:
@@ -4,7 +4,7 @@ This directory contains the BMAD Method installer implementation.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
```text
|
||||
installer/
|
||||
├── bin/ # CLI entry points
|
||||
│ └── bmad.js # Main CLI executable
|
||||
@@ -42,7 +42,7 @@ npx bmad-method install --profile=minimal
|
||||
|
||||
# Update existing installation
|
||||
npx bmad-method update
|
||||
```
|
||||
```text
|
||||
|
||||
## Development
|
||||
|
||||
@@ -55,4 +55,4 @@ npm test
|
||||
|
||||
# Lint code
|
||||
npm run lint
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,178 +1,139 @@
|
||||
# BMAD Method Installation Configuration
|
||||
# Simplified installer with two options: full copy or single agent
|
||||
|
||||
installation-options:
|
||||
full:
|
||||
name: "Complete BMAD Core"
|
||||
description: "Copy the entire .bmad-core folder with all agents, templates, and tools"
|
||||
action: "copy-folder"
|
||||
source: ".bmad-core"
|
||||
|
||||
name: Complete BMAD Core
|
||||
description: Copy the entire .bmad-core folder with all agents, templates, and tools
|
||||
action: copy-folder
|
||||
source: .bmad-core
|
||||
single-agent:
|
||||
name: "Single Agent"
|
||||
description: "Select and install a single agent with its dependencies"
|
||||
action: "copy-agent"
|
||||
|
||||
# Agent dependency mappings
|
||||
# These are the core files that should be included with any single agent installation
|
||||
name: Single Agent
|
||||
description: Select and install a single agent with its dependencies
|
||||
action: copy-agent
|
||||
agent-dependencies:
|
||||
core-files:
|
||||
# Only files that truly every agent needs should go here
|
||||
# Most dependencies should be declared in the agent YAML itself
|
||||
- ".bmad-core/utils/template-format.md"
|
||||
|
||||
# Agent-specific dependencies (parsed from agent files or explicitly defined)
|
||||
- .bmad-core/utils/template-format.md
|
||||
dev:
|
||||
- ".bmad-core/templates/story-tmpl.md"
|
||||
- ".bmad-core/checklists/story-dod-checklist.md"
|
||||
|
||||
- .bmad-core/templates/story-tmpl.md
|
||||
- .bmad-core/checklists/story-dod-checklist.md
|
||||
pm:
|
||||
- ".bmad-core/templates/prd-tmpl.md"
|
||||
- ".bmad-core/templates/brownfield-prd-tmpl.md"
|
||||
- ".bmad-core/checklists/pm-checklist.md"
|
||||
- ".bmad-core/checklists/change-checklist.md"
|
||||
- ".bmad-core/tasks/advanced-elicitation.md"
|
||||
- ".bmad-core/tasks/create-doc.md"
|
||||
- ".bmad-core/tasks/correct-course.md"
|
||||
- ".bmad-core/tasks/create-deep-research-prompt.md"
|
||||
- ".bmad-core/tasks/brownfield-create-epic.md"
|
||||
- ".bmad-core/tasks/brownfield-create-story.md"
|
||||
- ".bmad-core/tasks/execute-checklist.md"
|
||||
- ".bmad-core/tasks/shard-doc.md"
|
||||
|
||||
- .bmad-core/templates/prd-tmpl.md
|
||||
- .bmad-core/templates/brownfield-prd-tmpl.md
|
||||
- .bmad-core/checklists/pm-checklist.md
|
||||
- .bmad-core/checklists/change-checklist.md
|
||||
- .bmad-core/tasks/advanced-elicitation.md
|
||||
- .bmad-core/tasks/create-doc.md
|
||||
- .bmad-core/tasks/correct-course.md
|
||||
- .bmad-core/tasks/create-deep-research-prompt.md
|
||||
- .bmad-core/tasks/brownfield-create-epic.md
|
||||
- .bmad-core/tasks/brownfield-create-story.md
|
||||
- .bmad-core/tasks/execute-checklist.md
|
||||
- .bmad-core/tasks/shard-doc.md
|
||||
architect:
|
||||
- ".bmad-core/templates/architecture-tmpl.md"
|
||||
- ".bmad-core/checklists/architect-checklist.md"
|
||||
|
||||
- .bmad-core/templates/architecture-tmpl.md
|
||||
- .bmad-core/checklists/architect-checklist.md
|
||||
sm:
|
||||
- ".bmad-core/templates/story-tmpl.md"
|
||||
- ".bmad-core/checklists/story-draft-checklist.md"
|
||||
- ".bmad-core/workflows/*.yml"
|
||||
|
||||
- .bmad-core/templates/story-tmpl.md
|
||||
- .bmad-core/checklists/story-draft-checklist.md
|
||||
- .bmad-core/workflows/*.yml
|
||||
po:
|
||||
- ".bmad-core/checklists/po-master-checklist.md"
|
||||
- ".bmad-core/templates/acceptance-criteria-tmpl.md"
|
||||
|
||||
- .bmad-core/checklists/po-master-checklist.md
|
||||
- .bmad-core/templates/acceptance-criteria-tmpl.md
|
||||
analyst:
|
||||
- ".bmad-core/templates/prd-tmpl.md"
|
||||
- ".bmad-core/tasks/advanced-elicitation.md"
|
||||
|
||||
- .bmad-core/templates/prd-tmpl.md
|
||||
- .bmad-core/tasks/advanced-elicitation.md
|
||||
qa:
|
||||
- ".bmad-core/checklists/story-dod-checklist.md"
|
||||
- ".bmad-core/templates/test-plan-tmpl.md"
|
||||
|
||||
- .bmad-core/checklists/story-dod-checklist.md
|
||||
- .bmad-core/templates/test-plan-tmpl.md
|
||||
ux-expert:
|
||||
- ".bmad-core/templates/ux-tmpl.md"
|
||||
|
||||
# Meta agents typically need access to more resources
|
||||
- .bmad-core/templates/ux-tmpl.md
|
||||
bmad-master:
|
||||
- ".bmad-core/templates/*.md"
|
||||
- ".bmad-core/tasks/*.md"
|
||||
- ".bmad-core/schemas/*.yml"
|
||||
|
||||
- .bmad-core/templates/*.md
|
||||
- .bmad-core/tasks/*.md
|
||||
- .bmad-core/schemas/*.yml
|
||||
bmad-orchestrator:
|
||||
- ".bmad-core/agent-teams/*.yml"
|
||||
- ".bmad-core/workflows/*.yml"
|
||||
|
||||
# IDE-specific configuration for generating rules/commands
|
||||
- .bmad-core/agent-teams/*.yml
|
||||
- .bmad-core/workflows/*.yml
|
||||
ide-configurations:
|
||||
cursor:
|
||||
name: "Cursor"
|
||||
rule-dir: ".cursor/rules/"
|
||||
format: "multi-file"
|
||||
command-suffix: ".mdc"
|
||||
name: Cursor
|
||||
rule-dir: .cursor/rules/
|
||||
format: multi-file
|
||||
command-suffix: .mdc
|
||||
instructions: |
|
||||
# To use BMAD agents in Cursor:
|
||||
# 1. Press Ctrl+L (Cmd+L on Mac) to open the chat
|
||||
# 2. Type @agent-name (e.g., "@dev", "@pm", "@architect")
|
||||
# 3. The agent will adopt that persona for the conversation
|
||||
|
||||
claude-code:
|
||||
name: "Claude Code"
|
||||
rule-dir: ".claude/commands/"
|
||||
format: "multi-file"
|
||||
command-suffix: ".md"
|
||||
name: Claude Code
|
||||
rule-dir: .claude/commands/
|
||||
format: multi-file
|
||||
command-suffix: .md
|
||||
instructions: |
|
||||
# To use BMAD agents in Claude Code:
|
||||
# 1. Type /agent-name (e.g., "/dev", "/pm", "/architect")
|
||||
# 2. Claude will switch to that agent's persona
|
||||
|
||||
windsurf:
|
||||
name: "Windsurf"
|
||||
rule-dir: ".windsurf/rules/"
|
||||
format: "multi-file"
|
||||
command-suffix: ".md"
|
||||
name: Windsurf
|
||||
rule-dir: .windsurf/rules/
|
||||
format: multi-file
|
||||
command-suffix: .md
|
||||
instructions: |
|
||||
# To use BMAD agents in Windsurf:
|
||||
# 1. Type @agent-name (e.g., "@dev", "@pm")
|
||||
# 2. Windsurf will adopt that agent's persona
|
||||
|
||||
roo:
|
||||
name: "Roo Code"
|
||||
format: "custom-modes"
|
||||
file: ".roomodes"
|
||||
name: Roo Code
|
||||
format: custom-modes
|
||||
file: .roomodes
|
||||
instructions: |
|
||||
# To use BMAD agents in Roo Code:
|
||||
# 1. Open the mode selector (usually in the status bar)
|
||||
# 2. Select any bmad-{agent} mode (e.g., "bmad-dev", "bmad-pm")
|
||||
# 3. The AI will adopt that agent's full personality and capabilities
|
||||
|
||||
cline:
|
||||
name: "Cline"
|
||||
# Configuration TBD - needs research
|
||||
format: "unknown"
|
||||
name: Cline
|
||||
format: unknown
|
||||
instructions: |
|
||||
# Cline configuration coming soon
|
||||
# Manual setup: Copy IDE agent files to your Cline configuration
|
||||
|
||||
# Available agents for single-agent installation
|
||||
available-agents:
|
||||
- id: "analyst"
|
||||
name: "Business Analyst"
|
||||
file: ".bmad-core/agents/analyst.md"
|
||||
description: "Requirements gathering and analysis"
|
||||
|
||||
- id: "pm"
|
||||
name: "Product Manager"
|
||||
file: ".bmad-core/agents/pm.md"
|
||||
description: "Product strategy and roadmap planning"
|
||||
|
||||
- id: "architect"
|
||||
name: "Solution Architect"
|
||||
file: ".bmad-core/agents/architect.md"
|
||||
description: "Technical design and architecture"
|
||||
|
||||
- id: "po"
|
||||
name: "Product Owner"
|
||||
file: ".bmad-core/agents/po.md"
|
||||
description: "Backlog management and prioritization"
|
||||
|
||||
- id: "sm"
|
||||
name: "Scrum Master"
|
||||
file: ".bmad-core/agents/sm.md"
|
||||
description: "Agile process and story creation"
|
||||
|
||||
- id: "dev"
|
||||
name: "Developer"
|
||||
file: ".bmad-core/agents/dev.md"
|
||||
description: "Code implementation and testing"
|
||||
|
||||
- id: "qa"
|
||||
name: "QA Engineer"
|
||||
file: ".bmad-core/agents/qa.md"
|
||||
description: "Quality assurance and testing"
|
||||
|
||||
- id: "ux-expert"
|
||||
name: "UX Expert"
|
||||
file: ".bmad-core/agents/ux-expert.md"
|
||||
description: "User experience design"
|
||||
|
||||
- id: "bmad-master"
|
||||
name: "BMAD Master"
|
||||
file: ".bmad-core/agents/bmad-master.md"
|
||||
description: "BMAD framework expert and guide"
|
||||
|
||||
- id: "bmad-orchestrator"
|
||||
name: "BMAD Orchestrator"
|
||||
file: ".bmad-core/agents/bmad-orchestrator.md"
|
||||
description: "Multi-agent workflow coordinator"
|
||||
- id: analyst
|
||||
name: Business Analyst
|
||||
file: .bmad-core/agents/analyst.md
|
||||
description: Requirements gathering and analysis
|
||||
- id: pm
|
||||
name: Product Manager
|
||||
file: .bmad-core/agents/pm.md
|
||||
description: Product strategy and roadmap planning
|
||||
- id: architect
|
||||
name: Solution Architect
|
||||
file: .bmad-core/agents/architect.md
|
||||
description: Technical design and architecture
|
||||
- id: po
|
||||
name: Product Owner
|
||||
file: .bmad-core/agents/po.md
|
||||
description: Backlog management and prioritization
|
||||
- id: sm
|
||||
name: Scrum Master
|
||||
file: .bmad-core/agents/sm.md
|
||||
description: Agile process and story creation
|
||||
- id: dev
|
||||
name: Developer
|
||||
file: .bmad-core/agents/dev.md
|
||||
description: Code implementation and testing
|
||||
- id: qa
|
||||
name: QA Engineer
|
||||
file: .bmad-core/agents/qa.md
|
||||
description: Quality assurance and testing
|
||||
- id: ux-expert
|
||||
name: UX Expert
|
||||
file: .bmad-core/agents/ux-expert.md
|
||||
description: User experience design
|
||||
- id: bmad-master
|
||||
name: BMAD Master
|
||||
file: .bmad-core/agents/bmad-master.md
|
||||
description: BMAD framework expert and guide
|
||||
- id: bmad-orchestrator
|
||||
name: BMAD Orchestrator
|
||||
file: .bmad-core/agents/bmad-orchestrator.md
|
||||
description: Multi-agent workflow coordinator
|
||||
|
||||
@@ -331,7 +331,7 @@ class IdeSetup {
|
||||
? roleDefinitionMatch[1].trim()
|
||||
: `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
|
||||
|
||||
// Build mode entry with proper formatting
|
||||
// Build mode entry with proper formatting (matching exact indentation)
|
||||
newModesContent += ` - slug: bmad-${agentId}\n`;
|
||||
newModesContent += ` name: '${icon} ${title}'\n`;
|
||||
newModesContent += ` roleDefinition: ${roleDefinition}\n`;
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
---
|
||||
|
||||
This is a BMAD Method agent. For more information, visit: https://github.com/your-org/bmad-method
|
||||
This is a BMAD Method agent. For more information, visit: https://github.com/your-org/bmad-method
|
||||
|
||||
@@ -15,7 +15,8 @@ This file contains all BMAD Method agent personas. To use an agent, type its nam
|
||||
# Agent Switching
|
||||
|
||||
To switch between agents during a conversation:
|
||||
|
||||
1. Simply type the new agent name (e.g., "architect" or "dev")
|
||||
2. The AI will adopt that agent's persona
|
||||
|
||||
For more information about BMAD Method, visit: https://github.com/your-org/bmad-method
|
||||
For more information about BMAD Method, visit: https://github.com/your-org/bmad-method
|
||||
|
||||
@@ -19,4 +19,4 @@ This file contains all BMAD Method agent commands for Windsurf. Use /agent-name
|
||||
- Type `/architect` to switch to Architect persona
|
||||
- And so on for other agents...
|
||||
|
||||
For more information about BMAD Method, visit: https://github.com/your-org/bmad-method
|
||||
For more information about BMAD Method, visit: https://github.com/your-org/bmad-method
|
||||
|
||||
211
tools/yaml-format.js
Executable file
211
tools/yaml-format.js
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
const { execSync } = require('child_process');
|
||||
const chalk = require('chalk');
|
||||
|
||||
/**
|
||||
* YAML Formatter and Linter for BMAD-METHOD
|
||||
* Formats and validates YAML files and YAML embedded in Markdown
|
||||
*/
|
||||
|
||||
function formatYamlContent(content, filename) {
|
||||
try {
|
||||
// First try to fix common YAML issues
|
||||
let fixedContent = content
|
||||
// Fix "commands :" -> "commands:"
|
||||
.replace(/^(\s*)(\w+)\s+:/gm, '$1$2:')
|
||||
// Fix inconsistent list indentation
|
||||
.replace(/^(\s*)-\s{3,}/gm, '$1- ');
|
||||
|
||||
// Skip auto-fixing for .roomodes files - they have special nested structure
|
||||
if (!filename.includes('.roomodes')) {
|
||||
fixedContent = fixedContent
|
||||
// Fix unquoted list items that contain special characters or multiple parts
|
||||
.replace(/^(\s*)-\s+(.*)$/gm, (match, indent, content) => {
|
||||
// Skip if already quoted
|
||||
if (content.startsWith('"') && content.endsWith('"')) {
|
||||
return match;
|
||||
}
|
||||
// If the content contains special YAML characters or looks complex, quote it
|
||||
// BUT skip if it looks like a proper YAML key-value pair (like "key: value")
|
||||
if ((content.includes(':') || content.includes('-') || content.includes('{') || content.includes('}')) &&
|
||||
!content.match(/^\w+:\s/)) {
|
||||
// Remove any existing quotes first, escape internal quotes, then add proper quotes
|
||||
const cleanContent = content.replace(/^["']|["']$/g, '').replace(/"/g, '\\"');
|
||||
return `${indent}- "${cleanContent}"`;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
}
|
||||
|
||||
// Debug: show what we're trying to parse
|
||||
if (fixedContent !== content) {
|
||||
console.log(chalk.blue(`🔧 Applied YAML fixes to ${filename}`));
|
||||
}
|
||||
|
||||
// Parse and re-dump YAML to format it
|
||||
const parsed = yaml.load(fixedContent);
|
||||
const formatted = yaml.dump(parsed, {
|
||||
indent: 2,
|
||||
lineWidth: -1, // Disable line wrapping
|
||||
noRefs: true,
|
||||
sortKeys: false // Preserve key order
|
||||
});
|
||||
return formatted;
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`❌ YAML syntax error in ${filename}:`), error.message);
|
||||
console.error(chalk.yellow(`💡 Try manually fixing the YAML structure first`));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function processMarkdownFile(filePath) {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
let modified = false;
|
||||
let newContent = content;
|
||||
|
||||
// Fix untyped code blocks by adding 'text' type
|
||||
// Match ``` at start of line followed by newline, but only if it's an opening fence
|
||||
newContent = newContent.replace(/^```\n([\s\S]*?)\n```$/gm, '```text\n$1\n```');
|
||||
if (newContent !== content) {
|
||||
modified = true;
|
||||
console.log(chalk.blue(`🔧 Added 'text' type to untyped code blocks in ${filePath}`));
|
||||
}
|
||||
|
||||
// Find YAML code blocks
|
||||
const yamlBlockRegex = /```ya?ml\n([\s\S]*?)\n```/g;
|
||||
|
||||
newContent = newContent.replace(yamlBlockRegex, (match, yamlContent) => {
|
||||
const formatted = formatYamlContent(yamlContent, filePath);
|
||||
if (formatted === null) {
|
||||
return match; // Keep original if parsing failed
|
||||
}
|
||||
|
||||
// Remove trailing newline that js-yaml adds
|
||||
const trimmedFormatted = formatted.replace(/\n$/, '');
|
||||
|
||||
if (trimmedFormatted !== yamlContent) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
return `\`\`\`yml\n${trimmedFormatted}\n\`\`\``;
|
||||
});
|
||||
|
||||
if (modified) {
|
||||
fs.writeFileSync(filePath, newContent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function processYamlFile(filePath) {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const formatted = formatYamlContent(content, filePath);
|
||||
|
||||
if (formatted === null) {
|
||||
return false; // Syntax error
|
||||
}
|
||||
|
||||
if (formatted !== content) {
|
||||
fs.writeFileSync(filePath, formatted);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lintYamlFile(filePath) {
|
||||
try {
|
||||
// Use yaml-lint for additional validation
|
||||
execSync(`npx yaml-lint "${filePath}"`, { stdio: 'pipe' });
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`❌ YAML lint error in ${filePath}:`));
|
||||
console.error(error.stdout?.toString() || error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const glob = require('glob');
|
||||
|
||||
if (args.length === 0) {
|
||||
console.error('Usage: node yaml-format.js <file1> [file2] ...');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let hasErrors = false;
|
||||
let hasChanges = false;
|
||||
let filesProcessed = [];
|
||||
|
||||
// Expand glob patterns and collect all files
|
||||
const allFiles = [];
|
||||
for (const arg of args) {
|
||||
if (arg.includes('*')) {
|
||||
// It's a glob pattern
|
||||
const matches = glob.sync(arg);
|
||||
allFiles.push(...matches);
|
||||
} else {
|
||||
// It's a direct file path
|
||||
allFiles.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
for (const filePath of allFiles) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
// Skip silently for glob patterns that don't match anything
|
||||
if (!args.some(arg => arg.includes('*') && filePath === arg)) {
|
||||
console.error(chalk.red(`❌ File not found: ${filePath}`));
|
||||
hasErrors = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const basename = path.basename(filePath).toLowerCase();
|
||||
|
||||
try {
|
||||
let changed = false;
|
||||
if (ext === '.md') {
|
||||
changed = processMarkdownFile(filePath);
|
||||
} else if (ext === '.yml' || ext === '.yaml' || basename.includes('roomodes') || basename.includes('.yml') || basename.includes('.yaml')) {
|
||||
// Handle YAML files and special cases like .roomodes
|
||||
changed = processYamlFile(filePath);
|
||||
|
||||
// Also run linting
|
||||
const lintPassed = lintYamlFile(filePath);
|
||||
if (!lintPassed) hasErrors = true;
|
||||
} else {
|
||||
// Skip silently for unsupported files
|
||||
continue;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
hasChanges = true;
|
||||
filesProcessed.push(filePath);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`❌ Error processing ${filePath}:`), error.message);
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
console.log(chalk.green(`\n✨ YAML formatting completed! Modified ${filesProcessed.length} files:`));
|
||||
filesProcessed.forEach(file => console.log(chalk.blue(` 📝 ${file}`)));
|
||||
}
|
||||
|
||||
if (hasErrors) {
|
||||
console.error(chalk.red('\n💥 Some files had errors. Please fix them before committing.'));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = { formatYamlContent, processMarkdownFile, processYamlFile };
|
||||
Reference in New Issue
Block a user