Compare commits

..

7 Commits

Author SHA1 Message Date
Brian
168fbefdf7 Merge branch 'main' into feat/transform-qa-agent-to-test-architect 2025-08-15 22:02:19 -04:00
Murat K Ozcan
ac90641d83 Merge branch 'main' into feat/transform-qa-agent-to-test-architect 2025-08-15 16:40:42 -05:00
Murat Ozcan
2a18c33c7f fix: addressed review comments from manjaroblack, round 1 2025-08-14 10:03:55 -05:00
Murat Ozcan
147d444aeb fix: addressed review comments from manjaroblack, round 1 2025-08-14 10:00:54 -05:00
Murat Ozcan
8d300dadf3 docs: refined the docs for test architect 2025-08-13 11:07:22 -05:00
Murat Ozcan
34e75bef96 feat: transform QA agent into Test Architect with advanced quality capabilities
- Add 6 specialized quality assessment commands
  - Implement risk-based testing with scoring
  - Create quality gate system with deterministic decisions
  - Add comprehensive test design and NFR validation
  - Update documentation with stage-based workflow integration
2025-08-12 13:03:32 -05:00
Murat Ozcan
b7a34b4fc6 feat: transform QA agent into Test Architect with advanced quality capabilities
- Add 6 specialized quality assessment commands
  - Implement risk-based testing with scoring
  - Create quality gate system with deterministic decisions
  - Add comprehensive test design and NFR validation
  - Update documentation with stage-based workflow integration
2025-08-12 12:59:22 -05:00
8 changed files with 227 additions and 294 deletions

View File

@@ -83,27 +83,6 @@ jobs:
;;
esac
# Check if calculated version already exists on NPM and increment if necessary
while npm view bmad-method@$NEW_VERSION version >/dev/null 2>&1; do
echo "Version $NEW_VERSION already exists, incrementing..."
IFS='.' read -ra NEW_VERSION_PARTS <<< "$NEW_VERSION"
NEW_MAJOR=${NEW_VERSION_PARTS[0]}
NEW_MINOR=${NEW_VERSION_PARTS[1]}
NEW_PATCH=${NEW_VERSION_PARTS[2]}
case "${{ github.event.inputs.version_bump }}" in
"major")
NEW_VERSION="$((NEW_MAJOR + 1)).0.0"
;;
"minor")
NEW_VERSION="$NEW_MAJOR.$((NEW_MINOR + 1)).0"
;;
"patch")
NEW_VERSION="$NEW_MAJOR.$NEW_MINOR.$((NEW_PATCH + 1))"
;;
esac
done
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "Promoting from $CURRENT_VERSION to $NEW_VERSION"
@@ -121,10 +100,9 @@ jobs:
- name: Commit stable release
run: |
git add .
git commit -m "feat: promote to stable ${{ steps.version.outputs.new_version }}
BREAKING CHANGE: Promote beta features to stable release
git commit -m "release: promote to stable ${{ steps.version.outputs.new_version }}
- Promote beta features to stable release
- Update version from ${{ steps.version.outputs.current_version }} to ${{ steps.version.outputs.new_version }}
- Automated promotion via GitHub Actions"

View File

@@ -686,4 +686,3 @@ Co-Authored-By: Claude <noreply@anthropic.com>
### Features
- add versioning and release automation ([0ea5e50](https://github.com/bmadcode/BMAD-METHOD/commit/0ea5e50aa7ace5946d0100c180dd4c0da3e2fd8c))
# Promote to stable release 5.0.0

141
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "bmad-method",
"version": "5.0.0",
"version": "4.36.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bmad-method",
"version": "5.0.0",
"version": "4.36.2",
"license": "MIT",
"dependencies": {
"@kayvan/markdown-tree-parser": "^1.5.0",
@@ -18,8 +18,7 @@
"ignore": "^7.0.5",
"inquirer": "^8.2.6",
"js-yaml": "^4.1.0",
"ora": "^5.4.1",
"semver": "^7.6.3"
"ora": "^5.4.1"
},
"bin": {
"bmad": "tools/bmad-npx-wrapper.js",
@@ -109,16 +108,6 @@
"url": "https://opencollective.com/babel"
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/generator": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
@@ -153,16 +142,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
@@ -1980,6 +1959,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@semantic-release/npm/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@semantic-release/npm/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
@@ -3349,6 +3341,19 @@
"node": ">=16"
}
},
"node_modules/conventional-changelog-writer/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/conventional-commits-filter": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz",
@@ -4902,6 +4907,19 @@
"node": ">=10"
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/istanbul-lib-report": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
@@ -5603,6 +5621,19 @@
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
@@ -6372,6 +6403,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/makeerror": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -7264,6 +7308,19 @@
"node": "^16.14.0 || >=18.0.0"
}
},
"node_modules/normalize-package-data/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -11120,6 +11177,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/semantic-release/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
@@ -11147,15 +11217,13 @@
}
},
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/semver-diff": {
@@ -11174,6 +11242,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semver-diff/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/semver-regex": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "bmad-method",
"version": "5.0.0",
"version": "4.37.0-beta.6",
"description": "Breakthrough Method of Agile AI-driven Development",
"main": "tools/cli.js",
"bin": {

View File

@@ -45,7 +45,7 @@ program
.option('-f, --full', 'Install complete BMad Method')
.option('-x, --expansion-only', 'Install only expansion packs (no bmad-core)')
.option('-d, --directory <path>', 'Installation directory')
.option('-i, --ide <ide...>', 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, crush, other)')
.option('-i, --ide <ide...>', 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, other)')
.option('-e, --expansion-packs <packs...>', 'Install specific expansion packs (can specify multiple)')
.action(async (options) => {
try {
@@ -373,7 +373,6 @@ async function promptInstallation() {
{ name: 'Cline', value: 'cline' },
{ name: 'Gemini CLI', value: 'gemini' },
{ name: 'Qwen Code', value: 'qwen-code' },
{ name: 'Crush', value: 'crush' },
{ name: 'Github Copilot', value: 'github-copilot' }
]
}

View File

@@ -28,16 +28,6 @@ ide-configurations:
# 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
crush:
name: Crush
rule-dir: .crush/commands/BMad/
format: multi-file
command-suffix: .md
instructions: |
# To use BMad agents in Crush:
# 1. Press CTRL + P and press TAB
# 2. Select agent or task
# 3. Crush will switch to that agent's persona / task
windsurf:
name: Windsurf
rule-dir: .windsurf/rules/

View File

@@ -45,8 +45,6 @@ class IdeSetup extends BaseIdeSetup {
return this.setupCursor(installDir, selectedAgent);
case "claude-code":
return this.setupClaudeCode(installDir, selectedAgent);
case "crush":
return this.setupCrush(installDir, selectedAgent);
case "windsurf":
return this.setupWindsurf(installDir, selectedAgent);
case "trae":
@@ -90,30 +88,6 @@ class IdeSetup extends BaseIdeSetup {
return true;
}
async setupCrush(installDir, selectedAgent) {
// Setup bmad-core commands
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
const coreTasks = await this.getCoreTaskIds(installDir);
await this.setupCrushForPackage(installDir, "core", coreSlashPrefix, coreAgents, coreTasks, ".bmad-core");
// Setup expansion pack commands
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
for (const packInfo of expansionPacks) {
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
const packAgents = await this.getExpansionPackAgents(packInfo.path);
const packTasks = await this.getExpansionPackTasks(packInfo.path);
if (packAgents.length > 0 || packTasks.length > 0) {
// Use the actual directory name where the expansion pack is installed
const rootPath = path.relative(installDir, packInfo.path);
await this.setupCrushForPackage(installDir, packInfo.name, packSlashPrefix, packAgents, packTasks, rootPath);
}
}
return true;
}
async setupClaudeCode(installDir, selectedAgent) {
// Setup bmad-core commands
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
@@ -226,94 +200,6 @@ class IdeSetup extends BaseIdeSetup {
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
}
async setupCrushForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
const commandsBaseDir = path.join(installDir, ".crush", "commands", slashPrefix);
const agentsDir = path.join(commandsBaseDir, "agents");
const tasksDir = path.join(commandsBaseDir, "tasks");
// Ensure directories exist
await fileManager.ensureDirectory(agentsDir);
await fileManager.ensureDirectory(tasksDir);
// Setup agents
for (const agentId of agentIds) {
// Find the agent file - for expansion packs, prefer the expansion pack version
let agentPath;
if (packageName !== "core") {
// For expansion packs, first try to find the agent in the expansion pack directory
const expansionPackPath = path.join(installDir, rootPath, "agents", `${agentId}.md`);
if (await fileManager.pathExists(expansionPackPath)) {
agentPath = expansionPackPath;
} else {
// Fall back to core if not found in expansion pack
agentPath = await this.findAgentPath(agentId, installDir);
}
} else {
// For core, use the normal search
agentPath = await this.findAgentPath(agentId, installDir);
}
const commandPath = path.join(agentsDir, `${agentId}.md`);
if (agentPath) {
// Create command file with agent content
let agentContent = await fileManager.readFile(agentPath);
// Replace {root} placeholder with the appropriate root path for this context
agentContent = agentContent.replace(/{root}/g, rootPath);
// Add command header
let commandContent = `# /${agentId} Command\n\n`;
commandContent += `When this command is used, adopt the following agent persona:\n\n`;
commandContent += agentContent;
await fileManager.writeFile(commandPath, commandContent);
console.log(chalk.green(`✓ Created agent command: /${agentId}`));
}
}
// Setup tasks
for (const taskId of taskIds) {
// Find the task file - for expansion packs, prefer the expansion pack version
let taskPath;
if (packageName !== "core") {
// For expansion packs, first try to find the task in the expansion pack directory
const expansionPackPath = path.join(installDir, rootPath, "tasks", `${taskId}.md`);
if (await fileManager.pathExists(expansionPackPath)) {
taskPath = expansionPackPath;
} else {
// Fall back to core if not found in expansion pack
taskPath = await this.findTaskPath(taskId, installDir);
}
} else {
// For core, use the normal search
taskPath = await this.findTaskPath(taskId, installDir);
}
const commandPath = path.join(tasksDir, `${taskId}.md`);
if (taskPath) {
// Create command file with task content
let taskContent = await fileManager.readFile(taskPath);
// Replace {root} placeholder with the appropriate root path for this context
taskContent = taskContent.replace(/{root}/g, rootPath);
// Add command header
let commandContent = `# /${taskId} Task\n\n`;
commandContent += `When this command is used, execute the following task:\n\n`;
commandContent += taskContent;
await fileManager.writeFile(commandPath, commandContent);
console.log(chalk.green(`✓ Created task command: /${taskId}`));
}
}
console.log(chalk.green(`\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`));
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
}
async setupWindsurf(installDir, selectedAgent) {
const windsurfRulesDir = path.join(installDir, ".windsurf", "rules");
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);

View File

@@ -1,6 +1,6 @@
{
"name": "bmad-method",
"version": "5.0.0",
"version": "4.37.0-beta.6",
"description": "BMad Method installer - AI-powered Agile development framework",
"main": "lib/installer.js",
"bin": {