Compare commits
7 Commits
e465beb26a
...
06bf882772
| Author | SHA1 | Date |
|---|---|---|
|
|
06bf882772 | |
|
|
e073aee30b | |
|
|
8f1cb7fb70 | |
|
|
a48fd4aae8 | |
|
|
75ec4aa504 | |
|
|
7b4875be79 | |
|
|
c57506464f |
|
|
@ -37,7 +37,7 @@ permissions:
|
|||
|
||||
jobs:
|
||||
publish:
|
||||
if: github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main'
|
||||
if: github.repository == 'bmad-code-org/BMAD-METHOD' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ build/*.txt
|
|||
# Environment variables
|
||||
.env
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ agent:
|
|||
|
||||
menu:
|
||||
- trigger: BP or fuzzy match on brainstorm-project
|
||||
exec: "{project-root}/_bmad/core/workflows/brainstorming/workflow.md"
|
||||
exec: "skill:bmad-brainstorming"
|
||||
data: "{project-root}/_bmad/bmm/data/project-context-template.md"
|
||||
description: "[BP] Brainstorm Project: Expert Guided Facilitation through a single or multiple techniques with a final report"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ bmm,anytime,Update Standards,US,,_bmad/bmm/agents/tech-writer/tech-writer.agent.
|
|||
bmm,anytime,Mermaid Generate,MG,,_bmad/bmm/agents/tech-writer/tech-writer.agent.yaml,,false,tech-writer,,"Create a Mermaid diagram based on user description. Will suggest diagram types if not specified.",planning_artifacts,"mermaid diagram",
|
||||
bmm,anytime,Validate Document,VD,,_bmad/bmm/agents/tech-writer/tech-writer.agent.yaml,,false,tech-writer,,"Review the specified document against documentation standards and best practices. Returns specific actionable improvement suggestions organized by priority.",planning_artifacts,"validation report",
|
||||
bmm,anytime,Explain Concept,EC,,_bmad/bmm/agents/tech-writer/tech-writer.agent.yaml,,false,tech-writer,,"Create clear technical explanations with examples and diagrams for complex concepts. Breaks down into digestible sections using task-oriented approach.",project_knowledge,"explanation",
|
||||
bmm,1-analysis,Brainstorm Project,BP,10,_bmad/core/workflows/brainstorming/workflow.md,bmad-brainstorming,false,analyst,data=_bmad/bmm/data/project-context-template.md,"Expert Guided Facilitation through a single or multiple techniques",planning_artifacts,"brainstorming session",
|
||||
bmm,1-analysis,Brainstorm Project,BP,10,skill:bmad-brainstorming,bmad-brainstorming,false,analyst,data=_bmad/bmm/data/project-context-template.md,"Expert Guided Facilitation through a single or multiple techniques",planning_artifacts,"brainstorming session",
|
||||
bmm,1-analysis,Market Research,MR,20,_bmad/bmm/workflows/1-analysis/research/workflow-market-research.md,bmad-bmm-market-research,false,analyst,Create Mode,"Market analysis competitive landscape customer needs and trends","planning_artifacts|project-knowledge","research documents",
|
||||
bmm,1-analysis,Domain Research,DR,21,_bmad/bmm/workflows/1-analysis/research/workflow-domain-research.md,bmad-bmm-domain-research,false,analyst,Create Mode,"Industry domain deep dive subject matter expertise and terminology","planning_artifacts|project_knowledge","research documents",
|
||||
bmm,1-analysis,Technical Research,TR,22,_bmad/bmm/workflows/1-analysis/research/workflow-technical-research.md,bmad-bmm-technical-research,false,analyst,Create Mode,"Technical feasibility architecture options and implementation approaches","planning_artifacts|project_knowledge","research documents",
|
||||
|
|
|
|||
|
|
|
@ -1,5 +1,5 @@
|
|||
module,phase,name,code,sequence,workflow-file,command,required,agent,options,description,output-location,outputs
|
||||
core,anytime,Brainstorming,BSP,,_bmad/core/workflows/brainstorming/workflow.md,bmad-brainstorming,false,analyst,,"Generate diverse ideas through interactive techniques. Use early in ideation phase or when stuck generating ideas.",{output_folder}/brainstorming/brainstorming-session-{{date}}.md,,
|
||||
core,anytime,Brainstorming,BSP,,skill:bmad-brainstorming,bmad-brainstorming,false,analyst,,"Generate diverse ideas through interactive techniques. Use early in ideation phase or when stuck generating ideas.",{output_folder}/brainstorming/brainstorming-session-{{date}}.md,,
|
||||
core,anytime,Party Mode,PM,,skill:bmad-party-mode,bmad-party-mode,false,party-mode facilitator,,"Orchestrate multi-agent discussions. Use when you need multiple agent perspectives or want agents to collaborate.",,
|
||||
core,anytime,bmad-help,BH,,skill:bmad-help,bmad-help,false,,,"Get unstuck by showing what workflow steps come next or answering BMad Method questions.",,
|
||||
core,anytime,Index Docs,ID,,skill:bmad-index-docs,bmad-index-docs,false,,,"Create lightweight index for quick LLM scanning. Use when LLM needs to understand available docs without loading everything.",,
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
name: bmad-brainstorming
|
||||
description: 'Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods. Use when the user says help me brainstorm or help me ideate.'
|
||||
---
|
||||
|
||||
Follow the instructions in [workflow.md](workflow.md).
|
||||
|
|
@ -0,0 +1 @@
|
|||
type: skill
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
---
|
||||
name: brainstorming
|
||||
description: 'Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods. Use when the user says help me brainstorm or help me ideate.'
|
||||
context_file: '' # Optional context file path for project-specific guidance
|
||||
---
|
||||
|
||||
|
|
@ -42,9 +40,8 @@ Load config from `{project-root}/_bmad/core/config.yaml` and resolve:
|
|||
|
||||
### Paths
|
||||
|
||||
- `installed_path` = `{project-root}/_bmad/core/workflows/brainstorming`
|
||||
- `template_path` = `{installed_path}/template.md`
|
||||
- `brain_techniques_path` = `{installed_path}/brain-methods.csv`
|
||||
- `template_path` = `./template.md`
|
||||
- `brain_techniques_path` = `./brain-methods.csv`
|
||||
- `brainstorming_session_output_file` = `{output_folder}/brainstorming/brainstorming-session-{{date}}-{{time}}.md` (evaluated once at workflow start)
|
||||
|
||||
All steps MUST reference `{brainstorming_session_output_file}` instead of the full path pattern.
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
---
|
||||
name: bmad-party-mode
|
||||
description: 'Orchestrates group discussions between all installed BMAD agents, enabling natural multi-agent conversations. Use when user requests party mode.'
|
||||
---
|
||||
|
||||
# Party Mode Workflow
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
canonicalId: bmad-brainstorming
|
||||
type: workflow
|
||||
description: "Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods"
|
||||
|
|
@ -81,6 +81,60 @@ async function createTestBmadFixture() {
|
|||
return fixtureDir;
|
||||
}
|
||||
|
||||
async function createSkillCollisionFixture() {
|
||||
const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-skill-collision-'));
|
||||
const fixtureDir = path.join(fixtureRoot, '_bmad');
|
||||
const configDir = path.join(fixtureDir, '_config');
|
||||
await fs.ensureDir(configDir);
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(configDir, 'agent-manifest.csv'),
|
||||
[
|
||||
'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path,canonicalId',
|
||||
'"bmad-master","BMAD Master","","","","","","","","core","_bmad/core/agents/bmad-master.md","bmad-master"',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(configDir, 'workflow-manifest.csv'),
|
||||
[
|
||||
'name,description,module,path,canonicalId',
|
||||
'"help","Workflow help","core","_bmad/core/workflows/help/workflow.md","bmad-help"',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
await fs.writeFile(path.join(configDir, 'task-manifest.csv'), 'name,displayName,description,module,path,standalone,canonicalId\n');
|
||||
await fs.writeFile(path.join(configDir, 'tool-manifest.csv'), 'name,displayName,description,module,path,standalone,canonicalId\n');
|
||||
await fs.writeFile(
|
||||
path.join(configDir, 'skill-manifest.csv'),
|
||||
[
|
||||
'canonicalId,name,description,module,path,install_to_bmad',
|
||||
'"bmad-help","bmad-help","Native help skill","core","_bmad/core/tasks/bmad-help/SKILL.md","true"',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
const skillDir = path.join(fixtureDir, 'core', 'tasks', 'bmad-help');
|
||||
await fs.ensureDir(skillDir);
|
||||
await fs.writeFile(
|
||||
path.join(skillDir, 'SKILL.md'),
|
||||
['---', 'name: bmad-help', 'description: Native help skill', '---', '', 'Use this skill directly.'].join('\n'),
|
||||
);
|
||||
|
||||
const agentDir = path.join(fixtureDir, 'core', 'agents');
|
||||
await fs.ensureDir(agentDir);
|
||||
await fs.writeFile(
|
||||
path.join(agentDir, 'bmad-master.md'),
|
||||
['---', 'name: BMAD Master', 'description: Master agent', '---', '', '<agent name="BMAD Master" title="Master">', '</agent>'].join(
|
||||
'\n',
|
||||
),
|
||||
);
|
||||
|
||||
return { root: fixtureRoot, bmadDir: fixtureDir };
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Suite
|
||||
*/
|
||||
|
|
@ -1770,6 +1824,50 @@ async function runTests() {
|
|||
|
||||
console.log('');
|
||||
|
||||
// ============================================================
|
||||
// Test 31: Skill-format installs report unique skill directories
|
||||
// ============================================================
|
||||
console.log(`${colors.yellow}Test Suite 31: Skill Count Reporting${colors.reset}\n`);
|
||||
|
||||
let collisionFixtureRoot = null;
|
||||
let collisionProjectDir = null;
|
||||
|
||||
try {
|
||||
clearCache();
|
||||
const collisionFixture = await createSkillCollisionFixture();
|
||||
collisionFixtureRoot = collisionFixture.root;
|
||||
collisionProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-antigravity-test-'));
|
||||
|
||||
const ideManager = new IdeManager();
|
||||
await ideManager.ensureInitialized();
|
||||
const result = await ideManager.setup('antigravity', collisionProjectDir, collisionFixture.bmadDir, {
|
||||
silent: true,
|
||||
selectedModules: ['core'],
|
||||
});
|
||||
|
||||
assert(result.success === true, 'Antigravity setup succeeds with overlapping skill names');
|
||||
assert(result.detail === '2 agents', 'Installer detail reports agents separately from skills');
|
||||
assert(result.handlerResult.results.skillDirectories === 2, 'Result exposes unique skill directory count');
|
||||
assert(result.handlerResult.results.agents === 2, 'Result retains generated agent write count');
|
||||
assert(result.handlerResult.results.workflows === 1, 'Result retains generated workflow count');
|
||||
assert(result.handlerResult.results.skills === 1, 'Result retains verbatim skill count');
|
||||
assert(
|
||||
await fs.pathExists(path.join(collisionProjectDir, '.agent', 'skills', 'bmad-agent-bmad-master', 'SKILL.md')),
|
||||
'Agent skill directory is created',
|
||||
);
|
||||
assert(
|
||||
await fs.pathExists(path.join(collisionProjectDir, '.agent', 'skills', 'bmad-help', 'SKILL.md')),
|
||||
'Overlapping skill directory is created once',
|
||||
);
|
||||
} catch (error) {
|
||||
assert(false, 'Skill-format unique count test succeeds', error.message);
|
||||
} finally {
|
||||
if (collisionProjectDir) await fs.remove(collisionProjectDir).catch(() => {});
|
||||
if (collisionFixtureRoot) await fs.remove(collisionFixtureRoot).catch(() => {});
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
// ============================================================
|
||||
// Summary
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -1153,12 +1153,6 @@ class Installer {
|
|||
preservedModules: modulesForCsvPreserve,
|
||||
});
|
||||
|
||||
addResult(
|
||||
'Manifests',
|
||||
'ok',
|
||||
`${manifestStats.workflows} workflows, ${manifestStats.agents} agents, ${manifestStats.tasks} tasks, ${manifestStats.tools} tools`,
|
||||
);
|
||||
|
||||
// Merge help catalogs
|
||||
message('Generating help catalog...');
|
||||
await this.mergeModuleHelpCatalogs(bmadDir);
|
||||
|
|
@ -1379,10 +1373,27 @@ class Installer {
|
|||
*/
|
||||
async renderInstallSummary(results, context = {}) {
|
||||
const color = await prompts.getColor();
|
||||
const selectedIdes = new Set((context.ides || []).map((ide) => String(ide).toLowerCase()));
|
||||
|
||||
// Build step lines with status indicators
|
||||
const lines = [];
|
||||
for (const r of results) {
|
||||
let stepLabel = null;
|
||||
|
||||
if (r.status !== 'ok') {
|
||||
stepLabel = r.step;
|
||||
} else if (r.step === 'Core') {
|
||||
stepLabel = 'BMAD';
|
||||
} else if (r.step.startsWith('Module: ')) {
|
||||
stepLabel = r.step;
|
||||
} else if (selectedIdes.has(String(r.step).toLowerCase())) {
|
||||
stepLabel = r.step;
|
||||
}
|
||||
|
||||
if (!stepLabel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let icon;
|
||||
if (r.status === 'ok') {
|
||||
icon = color.green('\u2713');
|
||||
|
|
@ -1392,7 +1403,11 @@ class Installer {
|
|||
icon = color.red('\u2717');
|
||||
}
|
||||
const detail = r.detail ? color.dim(` (${r.detail})`) : '';
|
||||
lines.push(` ${icon} ${r.step}${detail}`);
|
||||
lines.push(` ${icon} ${stepLabel}${detail}`);
|
||||
}
|
||||
|
||||
if ((context.ides || []).length === 0) {
|
||||
lines.push(` ${color.green('\u2713')} No IDE selected ${color.dim('(installed in _bmad only)')}`);
|
||||
}
|
||||
|
||||
// Context and warnings
|
||||
|
|
@ -1415,8 +1430,10 @@ class Installer {
|
|||
` Join our Discord: ${color.dim('https://discord.gg/gk8jAdXWmj')}`,
|
||||
` Star us on GitHub: ${color.dim('https://github.com/bmad-code-org/BMAD-METHOD/')}`,
|
||||
` Subscribe on YouTube: ${color.dim('https://www.youtube.com/@BMadCode')}`,
|
||||
` Invoke the ${color.cyan('bmad-help')} skill in your IDE Agent to get started`,
|
||||
);
|
||||
if (context.ides && context.ides.length > 0) {
|
||||
lines.push(` Invoke the ${color.cyan('bmad-help')} skill in your IDE Agent to get started`);
|
||||
}
|
||||
|
||||
await prompts.note(lines.join('\n'), 'BMAD is ready to use!');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -349,7 +349,6 @@ class BaseIdeSetup {
|
|||
} else if (entry.isFile() && entry.name === 'workflow.md') {
|
||||
// Read workflow.md frontmatter to get name and standalone property
|
||||
try {
|
||||
const yaml = require('yaml');
|
||||
const content = await fs.readFile(fullPath, 'utf8');
|
||||
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
||||
if (!frontmatterMatch) continue;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
|
|||
|
||||
const selectedModules = options.selectedModules || [];
|
||||
const results = { agents: 0, workflows: 0, tasks: 0, tools: 0, skills: 0 };
|
||||
this.skillWriteTracker = config.skill_format ? new Set() : null;
|
||||
|
||||
// Install standard artifacts (agents, workflows, tasks, tools)
|
||||
if (!skipStandardArtifacts) {
|
||||
|
|
@ -159,9 +160,11 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
|
|||
// Install verbatim skills (type: skill)
|
||||
if (config.skill_format) {
|
||||
results.skills = await this.installVerbatimSkills(projectDir, bmadDir, targetPath, config);
|
||||
results.skillDirectories = this.skillWriteTracker ? this.skillWriteTracker.size : 0;
|
||||
}
|
||||
|
||||
await this.printSummary(results, target_dir, options);
|
||||
this.skillWriteTracker = null;
|
||||
return { success: true, results };
|
||||
}
|
||||
|
||||
|
|
@ -495,6 +498,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
|
|||
// Create skill directory
|
||||
const skillDir = path.join(targetPath, skillName);
|
||||
await this.ensureDir(skillDir);
|
||||
this.skillWriteTracker?.add(skillName);
|
||||
|
||||
// Transform content: rewrite frontmatter for skills format
|
||||
const skillContent = this.transformToSkillFormat(content, skillName);
|
||||
|
|
@ -667,6 +671,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
|
|||
const skillDir = path.join(targetPath, canonicalId);
|
||||
await fs.remove(skillDir);
|
||||
await fs.ensureDir(skillDir);
|
||||
this.skillWriteTracker?.add(canonicalId);
|
||||
|
||||
// Copy all skill files, filtering OS/editor artifacts recursively
|
||||
const skipPatterns = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']);
|
||||
|
|
@ -707,11 +712,11 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
|
|||
async printSummary(results, targetDir, options = {}) {
|
||||
if (options.silent) return;
|
||||
const parts = [];
|
||||
const totalDirs =
|
||||
results.skillDirectories || (results.workflows || 0) + (results.tasks || 0) + (results.tools || 0) + (results.skills || 0);
|
||||
const skillCount = totalDirs - (results.agents || 0);
|
||||
if (skillCount > 0) parts.push(`${skillCount} skills`);
|
||||
if (results.agents > 0) parts.push(`${results.agents} agents`);
|
||||
if (results.workflows > 0) parts.push(`${results.workflows} workflows`);
|
||||
if (results.tasks > 0) parts.push(`${results.tasks} tasks`);
|
||||
if (results.tools > 0) parts.push(`${results.tools} tools`);
|
||||
if (results.skills > 0) parts.push(`${results.skills} skills`);
|
||||
await prompts.log.success(`${this.name} configured: ${parts.join(', ')} → ${targetDir}`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,10 +162,10 @@ class IdeManager {
|
|||
// Config-driven handlers return { success, results: { agents, workflows, tasks, tools } }
|
||||
const r = handlerResult.results;
|
||||
const parts = [];
|
||||
const totalDirs = r.skillDirectories || (r.workflows || 0) + (r.tasks || 0) + (r.tools || 0) + (r.skills || 0);
|
||||
const skillCount = totalDirs - (r.agents || 0);
|
||||
if (skillCount > 0) parts.push(`${skillCount} skills`);
|
||||
if (r.agents > 0) parts.push(`${r.agents} agents`);
|
||||
if (r.workflows > 0) parts.push(`${r.workflows} workflows`);
|
||||
if (r.tasks > 0) parts.push(`${r.tasks} tasks`);
|
||||
if (r.tools > 0) parts.push(`${r.tools} tools`);
|
||||
detail = parts.join(', ');
|
||||
}
|
||||
// Propagate handler's success status (default true for backward compat)
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ function buildMenuXml(menuItems) {
|
|||
}
|
||||
}
|
||||
|
||||
xml += ` <item cmd="PM or fuzzy match on party-mode" exec="{project-root}/_bmad/core/workflows/bmad-party-mode/workflow.md">[PM] Start Party Mode</item>\n`;
|
||||
xml += ` <item cmd="PM or fuzzy match on party-mode" exec="skill:bmad-party-mode">[PM] Start Party Mode</item>\n`;
|
||||
xml += ` <item cmd="DA or fuzzy match on exit, leave, goodbye or dismiss agent">[DA] Dismiss Agent</item>\n`;
|
||||
|
||||
xml += ' </menu>\n';
|
||||
|
|
|
|||
Loading…
Reference in New Issue