bmad-method 4.17.0 → 4.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/bmad-master.md +0 -1
- package/CHANGELOG.md +20 -0
- package/bmad-core/core-config.yml +0 -1
- package/{bmad-core → common}/tasks/create-doc.md +2 -2
- package/{expansion-packs/expansion-creator/common-tasks → common/tasks}/execute-checklist.md +2 -6
- package/common/utils/workflow-management.md +69 -0
- package/dist/agents/analyst.txt +2 -2
- package/dist/agents/architect.txt +4 -8
- package/dist/agents/bmad-master.txt +35 -270
- package/dist/agents/bmad-orchestrator.txt +33 -187
- package/dist/agents/dev.txt +2 -6
- package/dist/agents/pm.txt +4 -8
- package/dist/agents/po.txt +2 -6
- package/dist/agents/sm.txt +2 -6
- package/dist/agents/ux-expert.txt +4 -8
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +4 -8
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +2 -6
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +2 -6
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +35 -193
- package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +2 -2
- package/dist/expansion-packs/expansion-creator/agents/bmad-the-creator.txt +5 -5
- package/dist/teams/team-all.txt +35 -193
- package/dist/teams/team-fullstack.txt +35 -193
- package/dist/teams/team-ide-minimal.txt +35 -193
- package/dist/teams/team-no-ui.txt +35 -193
- package/docs/working-in-the-brownfield.md +2 -2
- package/expansion-packs/bmad-2d-phaser-game-dev/config.yml +5 -0
- package/expansion-packs/bmad-creator-tools/config.yml +5 -0
- package/expansion-packs/{expansion-creator → bmad-creator-tools}/tasks/generate-expansion-pack.md +5 -5
- package/expansion-packs/bmad-infrastructure-devops/config.yml +5 -0
- package/package.json +1 -1
- package/test-ide-paths.js +41 -0
- package/tools/builders/web-builder.js +60 -19
- package/tools/installer/config/ide-agent-config.yml +58 -0
- package/tools/installer/config/install.config.yml +0 -85
- package/tools/installer/lib/config-loader.js +89 -41
- package/tools/installer/lib/file-manager.js +1 -0
- package/tools/installer/lib/ide-setup.js +150 -116
- package/tools/installer/lib/installer.js +263 -9
- package/tools/installer/package.json +1 -1
- package/tools/lib/dependency-resolver.js +15 -0
- package/bmad-core/tasks/core-dump.md +0 -74
- package/bmad-core/tasks/execute-checklist.md +0 -97
- package/bmad-core/utils/file-resolution-context.md +0 -10
- package/bmad-core/utils/workflow-management.md +0 -223
- package/expansion-packs/bmad-2d-phaser-game-dev/manifest.yml +0 -45
- package/expansion-packs/bmad-infrastructure-devops/manifest.yml +0 -23
- package/expansion-packs/bmad-infrastructure-devops/tasks/create-doc.md +0 -74
- package/expansion-packs/expansion-creator/common-tasks/create-doc.md +0 -74
- package/expansion-packs/expansion-creator/manifest.yml +0 -12
- package/expansion-packs/expansion-creator/utils/template-format.md +0 -26
- package/expansion-packs/expansion-creator/utils/workflow-management.md +0 -223
- /package/{bmad-core → common}/utils/template-format.md +0 -0
- /package/expansion-packs/{expansion-creator → bmad-creator-tools}/README.md +0 -0
- /package/expansion-packs/{expansion-creator → bmad-creator-tools}/agents/bmad-the-creator.md +0 -0
- /package/expansion-packs/{expansion-creator → bmad-creator-tools}/tasks/create-agent.md +0 -0
- /package/expansion-packs/{expansion-creator → bmad-creator-tools}/templates/agent-teams-tmpl.md +0 -0
- /package/expansion-packs/{expansion-creator → bmad-creator-tools}/templates/agent-tmpl.md +0 -0
- /package/expansion-packs/{expansion-creator → bmad-creator-tools}/templates/expansion-pack-plan-tmpl.md +0 -0
- /package/{bmad-core/utils → tools/md-assets}/web-agent-startup-instructions.md +0 -0
|
@@ -8,50 +8,6 @@ installation-options:
|
|
|
8
8
|
name: Single Agent
|
|
9
9
|
description: Select and install a single agent with its dependencies
|
|
10
10
|
action: copy-agent
|
|
11
|
-
agent-dependencies:
|
|
12
|
-
core-files:
|
|
13
|
-
- bmad-core/utils/template-format.md
|
|
14
|
-
dev:
|
|
15
|
-
- bmad-core/templates/story-tmpl.md
|
|
16
|
-
- bmad-core/checklists/story-dod-checklist.md
|
|
17
|
-
pm:
|
|
18
|
-
- bmad-core/templates/prd-tmpl.md
|
|
19
|
-
- bmad-core/templates/brownfield-prd-tmpl.md
|
|
20
|
-
- bmad-core/checklists/pm-checklist.md
|
|
21
|
-
- bmad-core/checklists/change-checklist.md
|
|
22
|
-
- bmad-core/tasks/advanced-elicitation.md
|
|
23
|
-
- bmad-core/tasks/create-doc.md
|
|
24
|
-
- bmad-core/tasks/correct-course.md
|
|
25
|
-
- bmad-core/tasks/create-deep-research-prompt.md
|
|
26
|
-
- bmad-core/tasks/brownfield-create-epic.md
|
|
27
|
-
- bmad-core/tasks/brownfield-create-story.md
|
|
28
|
-
- bmad-core/tasks/execute-checklist.md
|
|
29
|
-
- bmad-core/tasks/shard-doc.md
|
|
30
|
-
architect:
|
|
31
|
-
- bmad-core/templates/architecture-tmpl.md
|
|
32
|
-
- bmad-core/checklists/architect-checklist.md
|
|
33
|
-
sm:
|
|
34
|
-
- bmad-core/templates/story-tmpl.md
|
|
35
|
-
- bmad-core/checklists/story-draft-checklist.md
|
|
36
|
-
- bmad-core/workflows/*.yml
|
|
37
|
-
po:
|
|
38
|
-
- bmad-core/checklists/po-master-checklist.md
|
|
39
|
-
- bmad-core/templates/acceptance-criteria-tmpl.md
|
|
40
|
-
analyst:
|
|
41
|
-
- bmad-core/templates/prd-tmpl.md
|
|
42
|
-
- bmad-core/tasks/advanced-elicitation.md
|
|
43
|
-
qa:
|
|
44
|
-
- bmad-core/checklists/story-dod-checklist.md
|
|
45
|
-
- bmad-core/templates/test-plan-tmpl.md
|
|
46
|
-
ux-expert:
|
|
47
|
-
- bmad-core/templates/ux-tmpl.md
|
|
48
|
-
bmad-master:
|
|
49
|
-
- bmad-core/templates/*.md
|
|
50
|
-
- bmad-core/tasks/*.md
|
|
51
|
-
- bmad-core/schemas/*.yml
|
|
52
|
-
bmad-orchestrator:
|
|
53
|
-
- bmad-core/agent-teams/*.yml
|
|
54
|
-
- bmad-core/workflows/*.yml
|
|
55
11
|
ide-configurations:
|
|
56
12
|
cursor:
|
|
57
13
|
name: Cursor
|
|
@@ -111,44 +67,3 @@ ide-configurations:
|
|
|
111
67
|
# 2. It also configures .gemini/settings.json to load all agent files.
|
|
112
68
|
# 3. Simply mention the agent in your prompt (e.g., "As @dev, ...").
|
|
113
69
|
# 4. The Gemini CLI will automatically have the context for that agent.
|
|
114
|
-
available-agents:
|
|
115
|
-
- id: analyst
|
|
116
|
-
name: Business Analyst
|
|
117
|
-
file: bmad-core/agents/analyst.md
|
|
118
|
-
description: Requirements gathering and analysis
|
|
119
|
-
- id: pm
|
|
120
|
-
name: Product Manager
|
|
121
|
-
file: bmad-core/agents/pm.md
|
|
122
|
-
description: Product strategy and roadmap planning
|
|
123
|
-
- id: architect
|
|
124
|
-
name: Solution Architect
|
|
125
|
-
file: bmad-core/agents/architect.md
|
|
126
|
-
description: Technical design and architecture
|
|
127
|
-
- id: po
|
|
128
|
-
name: Product Owner
|
|
129
|
-
file: bmad-core/agents/po.md
|
|
130
|
-
description: Backlog management and prioritization
|
|
131
|
-
- id: sm
|
|
132
|
-
name: Scrum Master
|
|
133
|
-
file: bmad-core/agents/sm.md
|
|
134
|
-
description: Agile process and story creation
|
|
135
|
-
- id: dev
|
|
136
|
-
name: Developer
|
|
137
|
-
file: bmad-core/agents/dev.md
|
|
138
|
-
description: Code implementation and testing
|
|
139
|
-
- id: qa
|
|
140
|
-
name: QA Engineer
|
|
141
|
-
file: bmad-core/agents/qa.md
|
|
142
|
-
description: Quality assurance and testing
|
|
143
|
-
- id: ux-expert
|
|
144
|
-
name: UX Expert
|
|
145
|
-
file: bmad-core/agents/ux-expert.md
|
|
146
|
-
description: User experience design
|
|
147
|
-
- id: bmad-master
|
|
148
|
-
name: BMAD Master
|
|
149
|
-
file: bmad-core/agents/bmad-master.md
|
|
150
|
-
description: BMAD framework expert and guide
|
|
151
|
-
- id: bmad-orchestrator
|
|
152
|
-
name: BMAD Orchestrator
|
|
153
|
-
file: bmad-core/agents/bmad-orchestrator.md
|
|
154
|
-
description: Multi-agent workflow coordinator
|
|
@@ -26,8 +26,47 @@ class ConfigLoader {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
async getAvailableAgents() {
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const agentsDir = path.join(this.getBmadCorePath(), 'agents');
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const entries = await fs.readdir(agentsDir, { withFileTypes: true });
|
|
33
|
+
const agents = [];
|
|
34
|
+
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
37
|
+
const agentPath = path.join(agentsDir, entry.name);
|
|
38
|
+
const agentId = path.basename(entry.name, '.md');
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const agentContent = await fs.readFile(agentPath, 'utf8');
|
|
42
|
+
|
|
43
|
+
// Extract YAML block from agent file
|
|
44
|
+
const yamlMatch = agentContent.match(/```yml\n([\s\S]*?)\n```/);
|
|
45
|
+
if (yamlMatch) {
|
|
46
|
+
const yamlContent = yaml.load(yamlMatch[1]);
|
|
47
|
+
const agentConfig = yamlContent.agent || {};
|
|
48
|
+
|
|
49
|
+
agents.push({
|
|
50
|
+
id: agentId,
|
|
51
|
+
name: agentConfig.title || agentConfig.name || agentId,
|
|
52
|
+
file: `bmad-core/agents/${entry.name}`,
|
|
53
|
+
description: agentConfig.whenToUse || 'No description available'
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.warn(`Failed to read agent ${entry.name}: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Sort agents by name for consistent display
|
|
63
|
+
agents.sort((a, b) => a.name.localeCompare(b.name));
|
|
64
|
+
|
|
65
|
+
return agents;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.warn(`Failed to read agents directory: ${error.message}`);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
31
70
|
}
|
|
32
71
|
|
|
33
72
|
async getAvailableExpansionPacks() {
|
|
@@ -38,24 +77,45 @@ class ConfigLoader {
|
|
|
38
77
|
const expansionPacks = [];
|
|
39
78
|
|
|
40
79
|
for (const entry of entries) {
|
|
41
|
-
if (entry.isDirectory()) {
|
|
42
|
-
const
|
|
80
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
81
|
+
const packPath = path.join(expansionPacksDir, entry.name);
|
|
82
|
+
const configPath = path.join(packPath, 'config.yml');
|
|
43
83
|
|
|
44
84
|
try {
|
|
45
|
-
|
|
46
|
-
const
|
|
85
|
+
// Read config.yml
|
|
86
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
87
|
+
const config = yaml.load(configContent);
|
|
47
88
|
|
|
48
89
|
expansionPacks.push({
|
|
49
90
|
id: entry.name,
|
|
50
|
-
name:
|
|
51
|
-
description:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
91
|
+
name: config.name || entry.name,
|
|
92
|
+
description: config['short-title'] || config.description || 'No description available',
|
|
93
|
+
fullDescription: config.description || config['short-title'] || 'No description available',
|
|
94
|
+
version: config.version || '1.0.0',
|
|
95
|
+
author: config.author || 'BMAD Team',
|
|
96
|
+
packPath: packPath,
|
|
97
|
+
dependencies: config.dependencies?.agents || []
|
|
56
98
|
});
|
|
57
99
|
} catch (error) {
|
|
58
|
-
|
|
100
|
+
// Fallback if config.yml doesn't exist or can't be read
|
|
101
|
+
console.warn(`Failed to read config for expansion pack ${entry.name}: ${error.message}`);
|
|
102
|
+
|
|
103
|
+
// Try to derive info from directory name as fallback
|
|
104
|
+
const name = entry.name
|
|
105
|
+
.split('-')
|
|
106
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
107
|
+
.join(' ');
|
|
108
|
+
|
|
109
|
+
expansionPacks.push({
|
|
110
|
+
id: entry.name,
|
|
111
|
+
name: name,
|
|
112
|
+
description: 'No description available',
|
|
113
|
+
fullDescription: 'No description available',
|
|
114
|
+
version: '1.0.0',
|
|
115
|
+
author: 'BMAD Team',
|
|
116
|
+
packPath: packPath,
|
|
117
|
+
dependencies: []
|
|
118
|
+
});
|
|
59
119
|
}
|
|
60
120
|
}
|
|
61
121
|
}
|
|
@@ -72,36 +132,24 @@ class ConfigLoader {
|
|
|
72
132
|
const DependencyResolver = require('../../lib/dependency-resolver');
|
|
73
133
|
const resolver = new DependencyResolver(path.join(__dirname, '..', '..', '..'));
|
|
74
134
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
depPaths.push(filePath);
|
|
90
|
-
}
|
|
135
|
+
const agentDeps = await resolver.resolveAgentDependencies(agentId);
|
|
136
|
+
|
|
137
|
+
// Convert to flat list of file paths
|
|
138
|
+
const depPaths = [];
|
|
139
|
+
|
|
140
|
+
// Core files and utilities are included automatically by DependencyResolver
|
|
141
|
+
|
|
142
|
+
// Add agent file itself is already handled by installer
|
|
143
|
+
|
|
144
|
+
// Add all resolved resources
|
|
145
|
+
for (const resource of agentDeps.resources) {
|
|
146
|
+
const filePath = `.bmad-core/${resource.type}/${resource.id}.md`;
|
|
147
|
+
if (!depPaths.includes(filePath)) {
|
|
148
|
+
depPaths.push(filePath);
|
|
91
149
|
}
|
|
92
|
-
|
|
93
|
-
return depPaths;
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.warn(`Failed to dynamically resolve dependencies for ${agentId}: ${error.message}`);
|
|
96
|
-
|
|
97
|
-
// Fall back to static config
|
|
98
|
-
const config = await this.load();
|
|
99
|
-
const dependencies = config['agent-dependencies'] || {};
|
|
100
|
-
const coreFiles = dependencies['core-files'] || [];
|
|
101
|
-
const agentDeps = dependencies[agentId] || [];
|
|
102
|
-
|
|
103
|
-
return [...coreFiles, ...agentDeps];
|
|
104
150
|
}
|
|
151
|
+
|
|
152
|
+
return depPaths;
|
|
105
153
|
}
|
|
106
154
|
|
|
107
155
|
async getIdeConfiguration(ide) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
+
const fs = require("fs-extra");
|
|
3
|
+
const yaml = require("js-yaml");
|
|
2
4
|
const fileManager = require("./file-manager");
|
|
3
5
|
const configLoader = require("./config-loader");
|
|
4
6
|
|
|
@@ -13,6 +15,27 @@ async function initializeModules() {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
class IdeSetup {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.ideAgentConfig = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async loadIdeAgentConfig() {
|
|
23
|
+
if (this.ideAgentConfig) return this.ideAgentConfig;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const configPath = path.join(__dirname, '..', 'config', 'ide-agent-config.yml');
|
|
27
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
28
|
+
this.ideAgentConfig = yaml.load(configContent);
|
|
29
|
+
return this.ideAgentConfig;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.warn('Failed to load IDE agent configuration, using defaults');
|
|
32
|
+
return {
|
|
33
|
+
'roo-permissions': {},
|
|
34
|
+
'cline-order': {}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
async setup(ide, installDir, selectedAgent = null) {
|
|
17
40
|
await initializeModules();
|
|
18
41
|
const ideConfig = await configLoader.getIdeConfiguration(ide);
|
|
@@ -48,13 +71,10 @@ class IdeSetup {
|
|
|
48
71
|
await fileManager.ensureDirectory(cursorRulesDir);
|
|
49
72
|
|
|
50
73
|
for (const agentId of agents) {
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
if (!(await fileManager.pathExists(agentPath))) {
|
|
54
|
-
agentPath = path.join(installDir, "agents", `${agentId}.md`);
|
|
55
|
-
}
|
|
74
|
+
// Find the agent file
|
|
75
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
56
76
|
|
|
57
|
-
if (
|
|
77
|
+
if (agentPath) {
|
|
58
78
|
const agentContent = await fileManager.readFile(agentPath);
|
|
59
79
|
const mdcPath = path.join(cursorRulesDir, `${agentId}.mdc`);
|
|
60
80
|
|
|
@@ -65,8 +85,9 @@ class IdeSetup {
|
|
|
65
85
|
mdcContent += "alwaysApply: false\n";
|
|
66
86
|
mdcContent += "---\n\n";
|
|
67
87
|
mdcContent += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
68
|
-
mdcContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(
|
|
69
|
-
agentId
|
|
88
|
+
mdcContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
|
|
89
|
+
agentId,
|
|
90
|
+
installDir
|
|
70
91
|
)} agent persona.\n\n`;
|
|
71
92
|
mdcContent += "## Agent Activation\n\n";
|
|
72
93
|
mdcContent +=
|
|
@@ -82,10 +103,12 @@ class IdeSetup {
|
|
|
82
103
|
}
|
|
83
104
|
mdcContent += "\n```\n\n";
|
|
84
105
|
mdcContent += "## File Reference\n\n";
|
|
85
|
-
|
|
106
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
107
|
+
mdcContent += `The complete agent definition is available in [${relativePath}](mdc:${relativePath}).\n\n`;
|
|
86
108
|
mdcContent += "## Usage\n\n";
|
|
87
|
-
mdcContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(
|
|
88
|
-
agentId
|
|
109
|
+
mdcContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
110
|
+
agentId,
|
|
111
|
+
installDir
|
|
89
112
|
)} persona and follow all instructions defined in the YML configuration above.\n`;
|
|
90
113
|
|
|
91
114
|
await fileManager.writeFile(mdcPath, mdcContent);
|
|
@@ -105,14 +128,11 @@ class IdeSetup {
|
|
|
105
128
|
await fileManager.ensureDirectory(commandsDir);
|
|
106
129
|
|
|
107
130
|
for (const agentId of agents) {
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
if (!(await fileManager.pathExists(agentPath))) {
|
|
111
|
-
agentPath = path.join(installDir, "agents", `${agentId}.md`);
|
|
112
|
-
}
|
|
131
|
+
// Find the agent file
|
|
132
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
113
133
|
const commandPath = path.join(commandsDir, `${agentId}.md`);
|
|
114
134
|
|
|
115
|
-
if (
|
|
135
|
+
if (agentPath) {
|
|
116
136
|
// Create command file with agent content
|
|
117
137
|
const agentContent = await fileManager.readFile(agentPath);
|
|
118
138
|
|
|
@@ -138,20 +158,18 @@ class IdeSetup {
|
|
|
138
158
|
await fileManager.ensureDirectory(windsurfRulesDir);
|
|
139
159
|
|
|
140
160
|
for (const agentId of agents) {
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
if (!(await fileManager.pathExists(agentPath))) {
|
|
144
|
-
agentPath = path.join(installDir, "agents", `${agentId}.md`);
|
|
145
|
-
}
|
|
161
|
+
// Find the agent file
|
|
162
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
146
163
|
|
|
147
|
-
if (
|
|
164
|
+
if (agentPath) {
|
|
148
165
|
const agentContent = await fileManager.readFile(agentPath);
|
|
149
166
|
const mdPath = path.join(windsurfRulesDir, `${agentId}.md`);
|
|
150
167
|
|
|
151
168
|
// Create MD content (similar to Cursor but without frontmatter)
|
|
152
169
|
let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
153
|
-
mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(
|
|
154
|
-
agentId
|
|
170
|
+
mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
|
|
171
|
+
agentId,
|
|
172
|
+
installDir
|
|
155
173
|
)} agent persona.\n\n`;
|
|
156
174
|
mdContent += "## Agent Activation\n\n";
|
|
157
175
|
mdContent +=
|
|
@@ -167,10 +185,12 @@ class IdeSetup {
|
|
|
167
185
|
}
|
|
168
186
|
mdContent += "\n```\n\n";
|
|
169
187
|
mdContent += "## File Reference\n\n";
|
|
170
|
-
|
|
188
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
189
|
+
mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
171
190
|
mdContent += "## Usage\n\n";
|
|
172
|
-
mdContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(
|
|
173
|
-
agentId
|
|
191
|
+
mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
192
|
+
agentId,
|
|
193
|
+
installDir
|
|
174
194
|
)} persona and follow all instructions defined in the YML configuration above.\n`;
|
|
175
195
|
|
|
176
196
|
await fileManager.writeFile(mdPath, mdContent);
|
|
@@ -183,32 +203,93 @@ class IdeSetup {
|
|
|
183
203
|
return true;
|
|
184
204
|
}
|
|
185
205
|
|
|
206
|
+
async findAgentPath(agentId, installDir) {
|
|
207
|
+
// Try to find the agent file in various locations
|
|
208
|
+
const possiblePaths = [
|
|
209
|
+
path.join(installDir, ".bmad-core", "agents", `${agentId}.md`),
|
|
210
|
+
path.join(installDir, "agents", `${agentId}.md`)
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
// Also check expansion pack directories
|
|
214
|
+
const glob = require("glob");
|
|
215
|
+
const expansionDirs = glob.sync(".*/agents", { cwd: installDir });
|
|
216
|
+
for (const expDir of expansionDirs) {
|
|
217
|
+
possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
for (const agentPath of possiblePaths) {
|
|
221
|
+
if (await fileManager.pathExists(agentPath)) {
|
|
222
|
+
return agentPath;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
|
|
186
229
|
async getAllAgentIds(installDir) {
|
|
187
|
-
|
|
230
|
+
const glob = require("glob");
|
|
231
|
+
const allAgentIds = [];
|
|
232
|
+
|
|
233
|
+
// Check core agents in .bmad-core or root
|
|
188
234
|
let agentsDir = path.join(installDir, ".bmad-core", "agents");
|
|
189
235
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
190
236
|
agentsDir = path.join(installDir, "agents");
|
|
191
237
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
238
|
+
|
|
239
|
+
if (await fileManager.pathExists(agentsDir)) {
|
|
240
|
+
const agentFiles = glob.sync("*.md", { cwd: agentsDir });
|
|
241
|
+
allAgentIds.push(...agentFiles.map((file) => path.basename(file, ".md")));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Also check for expansion pack agents in dot folders
|
|
245
|
+
const expansionDirs = glob.sync(".*/agents", { cwd: installDir });
|
|
246
|
+
for (const expDir of expansionDirs) {
|
|
247
|
+
const fullExpDir = path.join(installDir, expDir);
|
|
248
|
+
const expAgentFiles = glob.sync("*.md", { cwd: fullExpDir });
|
|
249
|
+
allAgentIds.push(...expAgentFiles.map((file) => path.basename(file, ".md")));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Remove duplicates
|
|
253
|
+
return [...new Set(allAgentIds)];
|
|
196
254
|
}
|
|
197
255
|
|
|
198
|
-
getAgentTitle(agentId) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
256
|
+
async getAgentTitle(agentId, installDir) {
|
|
257
|
+
// Try to find the agent file in various locations
|
|
258
|
+
const possiblePaths = [
|
|
259
|
+
path.join(installDir, ".bmad-core", "agents", `${agentId}.md`),
|
|
260
|
+
path.join(installDir, "agents", `${agentId}.md`)
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
// Also check expansion pack directories
|
|
264
|
+
const glob = require("glob");
|
|
265
|
+
const expansionDirs = glob.sync(".*/agents", { cwd: installDir });
|
|
266
|
+
for (const expDir of expansionDirs) {
|
|
267
|
+
possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
for (const agentPath of possiblePaths) {
|
|
271
|
+
if (await fileManager.pathExists(agentPath)) {
|
|
272
|
+
try {
|
|
273
|
+
const agentContent = await fileManager.readFile(agentPath);
|
|
274
|
+
const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
|
|
275
|
+
|
|
276
|
+
if (yamlMatch) {
|
|
277
|
+
const yaml = yamlMatch[1];
|
|
278
|
+
const titleMatch = yaml.match(/title:\s*(.+)/);
|
|
279
|
+
if (titleMatch) {
|
|
280
|
+
return titleMatch[1].trim();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
} catch (error) {
|
|
284
|
+
console.warn(`Failed to read agent title for ${agentId}: ${error.message}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Fallback to formatted agent ID
|
|
290
|
+
return agentId.split('-').map(word =>
|
|
291
|
+
word.charAt(0).toUpperCase() + word.slice(1)
|
|
292
|
+
).join(' ');
|
|
212
293
|
}
|
|
213
294
|
|
|
214
295
|
async setupRoo(installDir, selectedAgent) {
|
|
@@ -232,40 +313,9 @@ class IdeSetup {
|
|
|
232
313
|
// Create new modes content
|
|
233
314
|
let newModesContent = "";
|
|
234
315
|
|
|
235
|
-
//
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
fileRegex: "\\.(md|txt)$",
|
|
239
|
-
description: "Documentation and text files",
|
|
240
|
-
},
|
|
241
|
-
pm: {
|
|
242
|
-
fileRegex: "\\.(md|txt)$",
|
|
243
|
-
description: "Product documentation",
|
|
244
|
-
},
|
|
245
|
-
architect: {
|
|
246
|
-
fileRegex: "\\.(md|txt|yml|yaml|json)$",
|
|
247
|
-
description: "Architecture docs and configs",
|
|
248
|
-
},
|
|
249
|
-
dev: null, // Full edit access
|
|
250
|
-
qa: {
|
|
251
|
-
fileRegex: "\\.(test|spec)\\.(js|ts|jsx|tsx)$|\\.md$",
|
|
252
|
-
description: "Test files and documentation",
|
|
253
|
-
},
|
|
254
|
-
"ux-expert": {
|
|
255
|
-
fileRegex: "\\.(md|css|scss|html|jsx|tsx)$",
|
|
256
|
-
description: "Design-related files",
|
|
257
|
-
},
|
|
258
|
-
po: {
|
|
259
|
-
fileRegex: "\\.(md|txt)$",
|
|
260
|
-
description: "Story and requirement docs",
|
|
261
|
-
},
|
|
262
|
-
sm: {
|
|
263
|
-
fileRegex: "\\.(md|txt)$",
|
|
264
|
-
description: "Process and planning docs",
|
|
265
|
-
},
|
|
266
|
-
"bmad-orchestrator": null, // Full edit access
|
|
267
|
-
"bmad-master": null, // Full edit access
|
|
268
|
-
};
|
|
316
|
+
// Load dynamic agent permissions from configuration
|
|
317
|
+
const config = await this.loadIdeAgentConfig();
|
|
318
|
+
const agentPermissions = config['roo-permissions'] || {};
|
|
269
319
|
|
|
270
320
|
for (const agentId of agents) {
|
|
271
321
|
// Skip if already exists
|
|
@@ -275,12 +325,9 @@ class IdeSetup {
|
|
|
275
325
|
}
|
|
276
326
|
|
|
277
327
|
// Read agent file to extract all information
|
|
278
|
-
|
|
279
|
-
if (!(await fileManager.pathExists(agentPath))) {
|
|
280
|
-
agentPath = path.join(installDir, "agents", `${agentId}.md`);
|
|
281
|
-
}
|
|
328
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
282
329
|
|
|
283
|
-
if (
|
|
330
|
+
if (agentPath) {
|
|
284
331
|
const agentContent = await fileManager.readFile(agentPath);
|
|
285
332
|
|
|
286
333
|
// Extract YAML content
|
|
@@ -294,7 +341,7 @@ class IdeSetup {
|
|
|
294
341
|
const whenToUseMatch = yaml.match(/whenToUse:\s*"(.+)"/);
|
|
295
342
|
const roleDefinitionMatch = yaml.match(/roleDefinition:\s*"(.+)"/);
|
|
296
343
|
|
|
297
|
-
const title = titleMatch ? titleMatch[1].trim() : this.getAgentTitle(agentId);
|
|
344
|
+
const title = titleMatch ? titleMatch[1].trim() : await this.getAgentTitle(agentId, installDir);
|
|
298
345
|
const icon = iconMatch ? iconMatch[1].trim() : "🤖";
|
|
299
346
|
const whenToUse = whenToUseMatch ? whenToUseMatch[1].trim() : `Use for ${title} tasks`;
|
|
300
347
|
const roleDefinition = roleDefinitionMatch
|
|
@@ -306,7 +353,9 @@ class IdeSetup {
|
|
|
306
353
|
newModesContent += ` name: '${icon} ${title}'\n`;
|
|
307
354
|
newModesContent += ` roleDefinition: ${roleDefinition}\n`;
|
|
308
355
|
newModesContent += ` whenToUse: ${whenToUse}\n`;
|
|
309
|
-
|
|
356
|
+
// Get relative path from installDir to agent file
|
|
357
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
358
|
+
newModesContent += ` customInstructions: CRITICAL Read the full YML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode\n`;
|
|
310
359
|
newModesContent += ` groups:\n`;
|
|
311
360
|
newModesContent += ` - read\n`;
|
|
312
361
|
|
|
@@ -351,28 +400,15 @@ class IdeSetup {
|
|
|
351
400
|
|
|
352
401
|
await fileManager.ensureDirectory(clineRulesDir);
|
|
353
402
|
|
|
354
|
-
//
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
'bmad-orchestrator': 2,
|
|
358
|
-
'pm': 3,
|
|
359
|
-
'analyst': 4,
|
|
360
|
-
'architect': 5,
|
|
361
|
-
'po': 6,
|
|
362
|
-
'sm': 7,
|
|
363
|
-
'dev': 8,
|
|
364
|
-
'qa': 9,
|
|
365
|
-
'ux-expert': 10
|
|
366
|
-
};
|
|
403
|
+
// Load dynamic agent ordering from configuration
|
|
404
|
+
const config = await this.loadIdeAgentConfig();
|
|
405
|
+
const agentOrder = config['cline-order'] || {};
|
|
367
406
|
|
|
368
407
|
for (const agentId of agents) {
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
if (!(await fileManager.pathExists(agentPath))) {
|
|
372
|
-
agentPath = path.join(installDir, "agents", `${agentId}.md`);
|
|
373
|
-
}
|
|
408
|
+
// Find the agent file
|
|
409
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
374
410
|
|
|
375
|
-
if (
|
|
411
|
+
if (agentPath) {
|
|
376
412
|
const agentContent = await fileManager.readFile(agentPath);
|
|
377
413
|
|
|
378
414
|
// Get numeric prefix for ordering
|
|
@@ -381,8 +417,8 @@ class IdeSetup {
|
|
|
381
417
|
const mdPath = path.join(clineRulesDir, `${prefix}-${agentId}.md`);
|
|
382
418
|
|
|
383
419
|
// Create MD content for Cline (focused on project standards and role)
|
|
384
|
-
let mdContent = `# ${this.getAgentTitle(agentId)} Agent\n\n`;
|
|
385
|
-
mdContent += `This rule defines the ${this.getAgentTitle(agentId)} persona and project standards.\n\n`;
|
|
420
|
+
let mdContent = `# ${await this.getAgentTitle(agentId, installDir)} Agent\n\n`;
|
|
421
|
+
mdContent += `This rule defines the ${await this.getAgentTitle(agentId, installDir)} persona and project standards.\n\n`;
|
|
386
422
|
mdContent += "## Role Definition\n\n";
|
|
387
423
|
mdContent +=
|
|
388
424
|
"When the user types `@" + agentId + "`, adopt this persona and follow these guidelines:\n\n";
|
|
@@ -400,9 +436,10 @@ class IdeSetup {
|
|
|
400
436
|
mdContent += `- Always maintain consistency with project documentation in .bmad-core/\n`;
|
|
401
437
|
mdContent += `- Follow the agent's specific guidelines and constraints\n`;
|
|
402
438
|
mdContent += `- Update relevant project files when making changes\n`;
|
|
403
|
-
|
|
439
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
440
|
+
mdContent += `- Reference the complete agent definition in [${relativePath}](${relativePath})\n\n`;
|
|
404
441
|
mdContent += "## Usage\n\n";
|
|
405
|
-
mdContent += `Type \`@${agentId}\` to activate this ${this.getAgentTitle(agentId)} persona.\n`;
|
|
442
|
+
mdContent += `Type \`@${agentId}\` to activate this ${await this.getAgentTitle(agentId, installDir)} persona.\n`;
|
|
406
443
|
|
|
407
444
|
await fileManager.writeFile(mdPath, mdContent);
|
|
408
445
|
console.log(chalk.green(`✓ Created rule: ${prefix}-${agentId}.md`));
|
|
@@ -426,12 +463,9 @@ class IdeSetup {
|
|
|
426
463
|
|
|
427
464
|
for (const agentId of agents) {
|
|
428
465
|
// Find the source agent file
|
|
429
|
-
|
|
430
|
-
if (!(await fileManager.pathExists(agentPath))) {
|
|
431
|
-
agentPath = path.join(installDir, "agents", `${agentId}.md`);
|
|
432
|
-
}
|
|
466
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
433
467
|
|
|
434
|
-
if (
|
|
468
|
+
if (agentPath) {
|
|
435
469
|
const agentContent = await fileManager.readFile(agentPath);
|
|
436
470
|
const contextFilePath = path.join(agentsContextDir, `${agentId}.md`);
|
|
437
471
|
|