bmad-method 6.2.1-next.0 โ 6.2.1-next.2
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/package.json +1 -1
- package/src/bmm/agents/bmad-agent-analyst/SKILL.md +58 -0
- package/src/bmm/agents/bmad-agent-analyst/bmad-manifest.json +44 -0
- package/src/bmm/agents/bmad-agent-analyst/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-architect/SKILL.md +58 -0
- package/src/bmm/agents/bmad-agent-architect/bmad-manifest.json +20 -0
- package/src/bmm/agents/bmad-agent-architect/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-dev/SKILL.md +68 -0
- package/src/bmm/agents/bmad-agent-dev/bmad-manifest.json +20 -0
- package/src/bmm/agents/bmad-agent-dev/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-pm/SKILL.md +59 -0
- package/src/bmm/agents/bmad-agent-pm/bmad-manifest.json +44 -0
- package/src/bmm/agents/bmad-agent-pm/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-qa/SKILL.md +66 -0
- package/src/bmm/agents/bmad-agent-qa/bmad-manifest.json +14 -0
- package/src/bmm/agents/bmad-agent-qa/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-quick-flow-solo-dev/SKILL.md +57 -0
- package/src/bmm/agents/bmad-agent-quick-flow-solo-dev/bmad-manifest.json +32 -0
- package/src/bmm/agents/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-sm/SKILL.md +57 -0
- package/src/bmm/agents/bmad-agent-sm/bmad-manifest.json +32 -0
- package/src/bmm/agents/bmad-agent-sm/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-tech-writer/SKILL.md +58 -0
- package/src/bmm/agents/bmad-agent-tech-writer/bmad-manifest.json +38 -0
- package/src/bmm/agents/bmad-agent-tech-writer/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/agents/bmad-agent-tech-writer/explain-concept.md +20 -0
- package/src/bmm/agents/bmad-agent-tech-writer/mermaid-gen.md +20 -0
- package/src/bmm/agents/bmad-agent-tech-writer/validate-doc.md +19 -0
- package/src/bmm/agents/bmad-agent-tech-writer/write-document.md +20 -0
- package/src/bmm/agents/bmad-agent-ux-designer/SKILL.md +60 -0
- package/src/bmm/agents/bmad-agent-ux-designer/bmad-manifest.json +14 -0
- package/src/bmm/agents/bmad-agent-ux-designer/bmad-skill-manifest.yaml +12 -0
- package/src/bmm/module-help.csv +5 -5
- package/src/core/skills/bmad-init/SKILL.md +100 -0
- package/src/core/skills/bmad-init/bmad-skill-manifest.yaml +1 -0
- package/src/core/skills/bmad-init/resources/core-module.yaml +25 -0
- package/src/core/skills/bmad-init/scripts/bmad_init.py +593 -0
- package/src/core/skills/bmad-init/scripts/tests/test_bmad_init.py +329 -0
- package/tools/cli/installers/lib/core/manifest-generator.js +43 -5
- package/tools/cli/installers/lib/ide/platform-codes.yaml +10 -0
- package/tools/platform-codes.yaml +6 -0
- package/src/bmm/agents/analyst.agent.yaml +0 -43
- package/src/bmm/agents/architect.agent.yaml +0 -29
- package/src/bmm/agents/dev.agent.yaml +0 -38
- package/src/bmm/agents/pm.agent.yaml +0 -44
- package/src/bmm/agents/qa.agent.yaml +0 -58
- package/src/bmm/agents/quick-flow-solo-dev.agent.yaml +0 -36
- package/src/bmm/agents/sm.agent.yaml +0 -37
- package/src/bmm/agents/tech-writer/bmad-skill-manifest.yaml +0 -3
- package/src/bmm/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +0 -224
- package/src/bmm/agents/tech-writer/tech-writer.agent.yaml +0 -46
- package/src/bmm/agents/ux-designer.agent.yaml +0 -27
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.10"
|
|
3
|
+
# dependencies = ["pyyaml"]
|
|
4
|
+
# ///
|
|
5
|
+
|
|
6
|
+
#!/usr/bin/env python3
|
|
7
|
+
"""Unit tests for bmad_init.py"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import shutil
|
|
12
|
+
import sys
|
|
13
|
+
import tempfile
|
|
14
|
+
import unittest
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
18
|
+
|
|
19
|
+
from bmad_init import (
|
|
20
|
+
find_project_root,
|
|
21
|
+
parse_var_specs,
|
|
22
|
+
resolve_project_root_placeholder,
|
|
23
|
+
expand_template,
|
|
24
|
+
apply_result_template,
|
|
25
|
+
load_module_yaml,
|
|
26
|
+
find_core_module_yaml,
|
|
27
|
+
find_target_module_yaml,
|
|
28
|
+
load_config_file,
|
|
29
|
+
load_module_config,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TestFindProjectRoot(unittest.TestCase):
|
|
34
|
+
|
|
35
|
+
def test_finds_bmad_folder(self):
|
|
36
|
+
temp_dir = tempfile.mkdtemp()
|
|
37
|
+
try:
|
|
38
|
+
(Path(temp_dir) / '_bmad').mkdir()
|
|
39
|
+
original_cwd = os.getcwd()
|
|
40
|
+
try:
|
|
41
|
+
os.chdir(temp_dir)
|
|
42
|
+
result = find_project_root()
|
|
43
|
+
self.assertEqual(result.resolve(), Path(temp_dir).resolve())
|
|
44
|
+
finally:
|
|
45
|
+
os.chdir(original_cwd)
|
|
46
|
+
finally:
|
|
47
|
+
shutil.rmtree(temp_dir)
|
|
48
|
+
|
|
49
|
+
def test_llm_provided_with_bmad(self):
|
|
50
|
+
temp_dir = tempfile.mkdtemp()
|
|
51
|
+
try:
|
|
52
|
+
(Path(temp_dir) / '_bmad').mkdir()
|
|
53
|
+
result = find_project_root(llm_provided=temp_dir)
|
|
54
|
+
self.assertEqual(result.resolve(), Path(temp_dir).resolve())
|
|
55
|
+
finally:
|
|
56
|
+
shutil.rmtree(temp_dir)
|
|
57
|
+
|
|
58
|
+
def test_llm_provided_without_bmad_still_returns_dir(self):
|
|
59
|
+
"""First-run case: LLM provides path but _bmad doesn't exist yet."""
|
|
60
|
+
temp_dir = tempfile.mkdtemp()
|
|
61
|
+
try:
|
|
62
|
+
result = find_project_root(llm_provided=temp_dir)
|
|
63
|
+
self.assertEqual(result.resolve(), Path(temp_dir).resolve())
|
|
64
|
+
finally:
|
|
65
|
+
shutil.rmtree(temp_dir)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestParseVarSpecs(unittest.TestCase):
|
|
69
|
+
|
|
70
|
+
def test_vars_with_defaults(self):
|
|
71
|
+
specs = parse_var_specs('var1:value1,var2:value2')
|
|
72
|
+
self.assertEqual(len(specs), 2)
|
|
73
|
+
self.assertEqual(specs[0]['name'], 'var1')
|
|
74
|
+
self.assertEqual(specs[0]['default'], 'value1')
|
|
75
|
+
|
|
76
|
+
def test_vars_without_defaults(self):
|
|
77
|
+
specs = parse_var_specs('var1,var2')
|
|
78
|
+
self.assertEqual(len(specs), 2)
|
|
79
|
+
self.assertIsNone(specs[0]['default'])
|
|
80
|
+
|
|
81
|
+
def test_mixed_vars(self):
|
|
82
|
+
specs = parse_var_specs('required_var,var2:default2')
|
|
83
|
+
self.assertIsNone(specs[0]['default'])
|
|
84
|
+
self.assertEqual(specs[1]['default'], 'default2')
|
|
85
|
+
|
|
86
|
+
def test_colon_in_default(self):
|
|
87
|
+
specs = parse_var_specs('path:{project-root}/some/path')
|
|
88
|
+
self.assertEqual(specs[0]['default'], '{project-root}/some/path')
|
|
89
|
+
|
|
90
|
+
def test_empty_string(self):
|
|
91
|
+
self.assertEqual(parse_var_specs(''), [])
|
|
92
|
+
|
|
93
|
+
def test_none(self):
|
|
94
|
+
self.assertEqual(parse_var_specs(None), [])
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TestResolveProjectRootPlaceholder(unittest.TestCase):
|
|
98
|
+
|
|
99
|
+
def test_resolve_placeholder(self):
|
|
100
|
+
result = resolve_project_root_placeholder('{project-root}/output', Path('/test'))
|
|
101
|
+
self.assertEqual(result, '/test/output')
|
|
102
|
+
|
|
103
|
+
def test_no_placeholder(self):
|
|
104
|
+
result = resolve_project_root_placeholder('/absolute/path', Path('/test'))
|
|
105
|
+
self.assertEqual(result, '/absolute/path')
|
|
106
|
+
|
|
107
|
+
def test_none(self):
|
|
108
|
+
self.assertIsNone(resolve_project_root_placeholder(None, Path('/test')))
|
|
109
|
+
|
|
110
|
+
def test_non_string(self):
|
|
111
|
+
self.assertEqual(resolve_project_root_placeholder(42, Path('/test')), 42)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TestExpandTemplate(unittest.TestCase):
|
|
115
|
+
|
|
116
|
+
def test_basic_expansion(self):
|
|
117
|
+
result = expand_template('{project-root}/output', {'project-root': '/test'})
|
|
118
|
+
self.assertEqual(result, '/test/output')
|
|
119
|
+
|
|
120
|
+
def test_multiple_placeholders(self):
|
|
121
|
+
result = expand_template(
|
|
122
|
+
'{output_folder}/planning',
|
|
123
|
+
{'output_folder': '_bmad-output', 'project-root': '/test'}
|
|
124
|
+
)
|
|
125
|
+
self.assertEqual(result, '_bmad-output/planning')
|
|
126
|
+
|
|
127
|
+
def test_none_value(self):
|
|
128
|
+
self.assertIsNone(expand_template(None, {}))
|
|
129
|
+
|
|
130
|
+
def test_non_string(self):
|
|
131
|
+
self.assertEqual(expand_template(42, {}), 42)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class TestApplyResultTemplate(unittest.TestCase):
|
|
135
|
+
|
|
136
|
+
def test_with_result_template(self):
|
|
137
|
+
var_def = {'result': '{project-root}/{value}'}
|
|
138
|
+
result = apply_result_template(var_def, '_bmad-output', {'project-root': '/test'})
|
|
139
|
+
self.assertEqual(result, '/test/_bmad-output')
|
|
140
|
+
|
|
141
|
+
def test_without_result_template(self):
|
|
142
|
+
result = apply_result_template({}, 'raw_value', {})
|
|
143
|
+
self.assertEqual(result, 'raw_value')
|
|
144
|
+
|
|
145
|
+
def test_value_only_template(self):
|
|
146
|
+
var_def = {'result': '{value}'}
|
|
147
|
+
result = apply_result_template(var_def, 'English', {})
|
|
148
|
+
self.assertEqual(result, 'English')
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class TestLoadModuleYaml(unittest.TestCase):
|
|
152
|
+
|
|
153
|
+
def setUp(self):
|
|
154
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
155
|
+
|
|
156
|
+
def tearDown(self):
|
|
157
|
+
shutil.rmtree(self.temp_dir)
|
|
158
|
+
|
|
159
|
+
def test_loads_core_module_yaml(self):
|
|
160
|
+
path = Path(self.temp_dir) / 'module.yaml'
|
|
161
|
+
path.write_text(
|
|
162
|
+
'code: core\n'
|
|
163
|
+
'name: "BMad Core Module"\n'
|
|
164
|
+
'header: "Core Config"\n'
|
|
165
|
+
'user_name:\n'
|
|
166
|
+
' prompt: "What should agents call you?"\n'
|
|
167
|
+
' default: "BMad"\n'
|
|
168
|
+
' result: "{value}"\n'
|
|
169
|
+
)
|
|
170
|
+
result = load_module_yaml(path)
|
|
171
|
+
self.assertIsNotNone(result)
|
|
172
|
+
self.assertEqual(result['meta']['code'], 'core')
|
|
173
|
+
self.assertEqual(result['meta']['name'], 'BMad Core Module')
|
|
174
|
+
self.assertIn('user_name', result['variables'])
|
|
175
|
+
self.assertEqual(result['variables']['user_name']['prompt'], 'What should agents call you?')
|
|
176
|
+
|
|
177
|
+
def test_loads_module_with_directories(self):
|
|
178
|
+
path = Path(self.temp_dir) / 'module.yaml'
|
|
179
|
+
path.write_text(
|
|
180
|
+
'code: bmm\n'
|
|
181
|
+
'name: "BMad Method"\n'
|
|
182
|
+
'project_name:\n'
|
|
183
|
+
' prompt: "Project name?"\n'
|
|
184
|
+
' default: "{directory_name}"\n'
|
|
185
|
+
' result: "{value}"\n'
|
|
186
|
+
'directories:\n'
|
|
187
|
+
' - "{planning_artifacts}"\n'
|
|
188
|
+
)
|
|
189
|
+
result = load_module_yaml(path)
|
|
190
|
+
self.assertEqual(result['directories'], ['{planning_artifacts}'])
|
|
191
|
+
|
|
192
|
+
def test_returns_none_for_missing(self):
|
|
193
|
+
result = load_module_yaml(Path(self.temp_dir) / 'nonexistent.yaml')
|
|
194
|
+
self.assertIsNone(result)
|
|
195
|
+
|
|
196
|
+
def test_returns_none_for_empty(self):
|
|
197
|
+
path = Path(self.temp_dir) / 'empty.yaml'
|
|
198
|
+
path.write_text('')
|
|
199
|
+
result = load_module_yaml(path)
|
|
200
|
+
self.assertIsNone(result)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class TestFindCoreModuleYaml(unittest.TestCase):
|
|
204
|
+
|
|
205
|
+
def test_returns_path_to_resources(self):
|
|
206
|
+
path = find_core_module_yaml()
|
|
207
|
+
self.assertTrue(str(path).endswith('resources/core-module.yaml'))
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class TestFindTargetModuleYaml(unittest.TestCase):
|
|
211
|
+
|
|
212
|
+
def setUp(self):
|
|
213
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
214
|
+
self.project_root = Path(self.temp_dir)
|
|
215
|
+
|
|
216
|
+
def tearDown(self):
|
|
217
|
+
shutil.rmtree(self.temp_dir)
|
|
218
|
+
|
|
219
|
+
def test_finds_in_skill_assets(self):
|
|
220
|
+
skill_path = self.project_root / 'skills' / 'test-skill'
|
|
221
|
+
assets = skill_path / 'assets'
|
|
222
|
+
assets.mkdir(parents=True)
|
|
223
|
+
(assets / 'module.yaml').write_text('code: test\n')
|
|
224
|
+
|
|
225
|
+
result = find_target_module_yaml('test', self.project_root, str(skill_path))
|
|
226
|
+
self.assertIsNotNone(result)
|
|
227
|
+
self.assertTrue(str(result).endswith('assets/module.yaml'))
|
|
228
|
+
|
|
229
|
+
def test_finds_in_skill_root(self):
|
|
230
|
+
skill_path = self.project_root / 'skills' / 'test-skill'
|
|
231
|
+
skill_path.mkdir(parents=True)
|
|
232
|
+
(skill_path / 'module.yaml').write_text('code: test\n')
|
|
233
|
+
|
|
234
|
+
result = find_target_module_yaml('test', self.project_root, str(skill_path))
|
|
235
|
+
self.assertIsNotNone(result)
|
|
236
|
+
|
|
237
|
+
def test_finds_in_bmad_module_dir(self):
|
|
238
|
+
module_dir = self.project_root / '_bmad' / 'mymod'
|
|
239
|
+
module_dir.mkdir(parents=True)
|
|
240
|
+
(module_dir / 'module.yaml').write_text('code: mymod\n')
|
|
241
|
+
|
|
242
|
+
result = find_target_module_yaml('mymod', self.project_root)
|
|
243
|
+
self.assertIsNotNone(result)
|
|
244
|
+
|
|
245
|
+
def test_returns_none_when_not_found(self):
|
|
246
|
+
result = find_target_module_yaml('missing', self.project_root)
|
|
247
|
+
self.assertIsNone(result)
|
|
248
|
+
|
|
249
|
+
def test_skill_path_takes_priority(self):
|
|
250
|
+
"""Skill assets module.yaml takes priority over _bmad/{module}/."""
|
|
251
|
+
skill_path = self.project_root / 'skills' / 'test-skill'
|
|
252
|
+
assets = skill_path / 'assets'
|
|
253
|
+
assets.mkdir(parents=True)
|
|
254
|
+
(assets / 'module.yaml').write_text('code: test\nname: from-skill\n')
|
|
255
|
+
|
|
256
|
+
module_dir = self.project_root / '_bmad' / 'test'
|
|
257
|
+
module_dir.mkdir(parents=True)
|
|
258
|
+
(module_dir / 'module.yaml').write_text('code: test\nname: from-bmad\n')
|
|
259
|
+
|
|
260
|
+
result = find_target_module_yaml('test', self.project_root, str(skill_path))
|
|
261
|
+
self.assertTrue('assets' in str(result))
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class TestLoadConfigFile(unittest.TestCase):
|
|
265
|
+
|
|
266
|
+
def setUp(self):
|
|
267
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
268
|
+
|
|
269
|
+
def tearDown(self):
|
|
270
|
+
shutil.rmtree(self.temp_dir)
|
|
271
|
+
|
|
272
|
+
def test_loads_flat_yaml(self):
|
|
273
|
+
path = Path(self.temp_dir) / 'config.yaml'
|
|
274
|
+
path.write_text('user_name: Test\ncommunication_language: English\n')
|
|
275
|
+
result = load_config_file(path)
|
|
276
|
+
self.assertEqual(result['user_name'], 'Test')
|
|
277
|
+
|
|
278
|
+
def test_returns_none_for_missing(self):
|
|
279
|
+
result = load_config_file(Path(self.temp_dir) / 'missing.yaml')
|
|
280
|
+
self.assertIsNone(result)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class TestLoadModuleConfig(unittest.TestCase):
|
|
284
|
+
|
|
285
|
+
def setUp(self):
|
|
286
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
287
|
+
self.project_root = Path(self.temp_dir)
|
|
288
|
+
bmad_core = self.project_root / '_bmad' / 'core'
|
|
289
|
+
bmad_core.mkdir(parents=True)
|
|
290
|
+
(bmad_core / 'config.yaml').write_text(
|
|
291
|
+
'user_name: TestUser\n'
|
|
292
|
+
'communication_language: English\n'
|
|
293
|
+
'document_output_language: English\n'
|
|
294
|
+
'output_folder: "{project-root}/_bmad-output"\n'
|
|
295
|
+
)
|
|
296
|
+
bmad_bmb = self.project_root / '_bmad' / 'bmb'
|
|
297
|
+
bmad_bmb.mkdir(parents=True)
|
|
298
|
+
(bmad_bmb / 'config.yaml').write_text(
|
|
299
|
+
'user_name: TestUser\n'
|
|
300
|
+
'communication_language: English\n'
|
|
301
|
+
'document_output_language: English\n'
|
|
302
|
+
'output_folder: "{project-root}/_bmad-output"\n'
|
|
303
|
+
'bmad_builder_output_folder: "{project-root}/_bmad-output/skills"\n'
|
|
304
|
+
'bmad_builder_reports: "{project-root}/_bmad-output/reports"\n'
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
def tearDown(self):
|
|
308
|
+
shutil.rmtree(self.temp_dir)
|
|
309
|
+
|
|
310
|
+
def test_load_core(self):
|
|
311
|
+
result = load_module_config('core', self.project_root)
|
|
312
|
+
self.assertIsNotNone(result)
|
|
313
|
+
self.assertEqual(result['user_name'], 'TestUser')
|
|
314
|
+
|
|
315
|
+
def test_load_module_includes_core_vars(self):
|
|
316
|
+
result = load_module_config('bmb', self.project_root)
|
|
317
|
+
self.assertIsNotNone(result)
|
|
318
|
+
# Module-specific var
|
|
319
|
+
self.assertIn('bmad_builder_output_folder', result)
|
|
320
|
+
# Core vars also present
|
|
321
|
+
self.assertEqual(result['user_name'], 'TestUser')
|
|
322
|
+
|
|
323
|
+
def test_missing_module(self):
|
|
324
|
+
result = load_module_config('nonexistent', self.project_root)
|
|
325
|
+
self.assertIsNone(result)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
if __name__ == '__main__':
|
|
329
|
+
unittest.main()
|
|
@@ -176,7 +176,7 @@ class ManifestGenerator {
|
|
|
176
176
|
const skillFile = 'SKILL.md';
|
|
177
177
|
const artifactType = this.getArtifactType(manifest, skillFile);
|
|
178
178
|
|
|
179
|
-
if (artifactType === 'skill') {
|
|
179
|
+
if (artifactType === 'skill' || artifactType === 'agent') {
|
|
180
180
|
const skillMdPath = path.join(dir, 'SKILL.md');
|
|
181
181
|
const dirName = path.basename(dir);
|
|
182
182
|
|
|
@@ -191,7 +191,8 @@ class ManifestGenerator {
|
|
|
191
191
|
: `${this.bmadFolderName}/${moduleName}/${skillFile}`;
|
|
192
192
|
|
|
193
193
|
// Skills derive canonicalId from directory name โ never from manifest
|
|
194
|
-
|
|
194
|
+
// (agent-type skills legitimately use canonicalId for agent-manifest mapping, so skip warning)
|
|
195
|
+
if (manifest && manifest.__single && manifest.__single.canonicalId && artifactType !== 'agent') {
|
|
195
196
|
console.warn(
|
|
196
197
|
`Warning: Skill manifest at ${dir}/bmad-skill-manifest.yaml contains canonicalId โ this field is ignored for skills (directory name is the canonical ID)`,
|
|
197
198
|
);
|
|
@@ -227,10 +228,10 @@ class ManifestGenerator {
|
|
|
227
228
|
if (manifest && !this.skillClaimedDirs.has(dir)) {
|
|
228
229
|
let hasSkillType = false;
|
|
229
230
|
if (manifest.__single) {
|
|
230
|
-
hasSkillType = manifest.__single.type === 'skill';
|
|
231
|
+
hasSkillType = manifest.__single.type === 'skill' || manifest.__single.type === 'agent';
|
|
231
232
|
} else {
|
|
232
233
|
for (const key of Object.keys(manifest)) {
|
|
233
|
-
if (manifest[key]?.type === 'skill') {
|
|
234
|
+
if (manifest[key]?.type === 'skill' || manifest[key]?.type === 'agent') {
|
|
234
235
|
hasSkillType = true;
|
|
235
236
|
break;
|
|
236
237
|
}
|
|
@@ -503,8 +504,45 @@ class ManifestGenerator {
|
|
|
503
504
|
const fullPath = path.join(dirPath, entry.name);
|
|
504
505
|
|
|
505
506
|
if (entry.isDirectory()) {
|
|
506
|
-
//
|
|
507
|
+
// Check for new-format agent: bmad-skill-manifest.yaml with type: agent
|
|
508
|
+
// Note: type:agent dirs may also be claimed by collectSkills for IDE installation,
|
|
509
|
+
// but we still need to process them here for agent-manifest.csv
|
|
510
|
+
const dirManifest = await this.loadSkillManifest(fullPath);
|
|
511
|
+
if (dirManifest && dirManifest.__single && dirManifest.__single.type === 'agent') {
|
|
512
|
+
const m = dirManifest.__single;
|
|
513
|
+
const dirRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
514
|
+
const installPath =
|
|
515
|
+
moduleName === 'core'
|
|
516
|
+
? `${this.bmadFolderName}/core/agents/${dirRelativePath}`
|
|
517
|
+
: `${this.bmadFolderName}/${moduleName}/agents/${dirRelativePath}`;
|
|
518
|
+
|
|
519
|
+
agents.push({
|
|
520
|
+
name: m.name || entry.name,
|
|
521
|
+
displayName: m.displayName || m.name || entry.name,
|
|
522
|
+
title: m.title || '',
|
|
523
|
+
icon: m.icon || '',
|
|
524
|
+
capabilities: m.capabilities ? this.cleanForCSV(m.capabilities) : '',
|
|
525
|
+
role: m.role ? this.cleanForCSV(m.role) : '',
|
|
526
|
+
identity: m.identity ? this.cleanForCSV(m.identity) : '',
|
|
527
|
+
communicationStyle: m.communicationStyle ? this.cleanForCSV(m.communicationStyle) : '',
|
|
528
|
+
principles: m.principles ? this.cleanForCSV(m.principles) : '',
|
|
529
|
+
module: m.module || moduleName,
|
|
530
|
+
path: installPath,
|
|
531
|
+
canonicalId: m.canonicalId || '',
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
this.files.push({
|
|
535
|
+
type: 'agent',
|
|
536
|
+
name: m.name || entry.name,
|
|
537
|
+
module: moduleName,
|
|
538
|
+
path: installPath,
|
|
539
|
+
});
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Skip directories claimed by collectSkills (non-agent type skills)
|
|
507
544
|
if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
|
|
545
|
+
|
|
508
546
|
// Recurse into subdirectories
|
|
509
547
|
const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
510
548
|
const subDirAgents = await this.getAgentsFromDir(fullPath, moduleName, newRelativePath);
|
|
@@ -176,6 +176,16 @@ platforms:
|
|
|
176
176
|
template_type: kiro
|
|
177
177
|
skill_format: true
|
|
178
178
|
|
|
179
|
+
ona:
|
|
180
|
+
name: "Ona"
|
|
181
|
+
preferred: false
|
|
182
|
+
category: ide
|
|
183
|
+
description: "Ona AI development environment"
|
|
184
|
+
installer:
|
|
185
|
+
target_dir: .ona/skills
|
|
186
|
+
template_type: default
|
|
187
|
+
skill_format: true
|
|
188
|
+
|
|
179
189
|
opencode:
|
|
180
190
|
name: "OpenCode"
|
|
181
191
|
preferred: false
|
|
@@ -127,6 +127,12 @@ platforms:
|
|
|
127
127
|
category: ide
|
|
128
128
|
description: "AI-powered IDE with cascade flows"
|
|
129
129
|
|
|
130
|
+
ona:
|
|
131
|
+
name: "Ona"
|
|
132
|
+
preferred: false
|
|
133
|
+
category: ide
|
|
134
|
+
description: "Ona AI development environment"
|
|
135
|
+
|
|
130
136
|
# Platform categories
|
|
131
137
|
categories:
|
|
132
138
|
ide:
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
agent:
|
|
2
|
-
metadata:
|
|
3
|
-
id: "_bmad/bmm/agents/analyst.md"
|
|
4
|
-
name: Mary
|
|
5
|
-
title: Business Analyst
|
|
6
|
-
icon: ๐
|
|
7
|
-
module: bmm
|
|
8
|
-
capabilities: "market research, competitive analysis, requirements elicitation, domain expertise"
|
|
9
|
-
hasSidecar: false
|
|
10
|
-
|
|
11
|
-
persona:
|
|
12
|
-
role: Strategic Business Analyst + Requirements Expert
|
|
13
|
-
identity: Senior analyst with deep expertise in market research, competitive analysis, and requirements elicitation. Specializes in translating vague needs into actionable specs.
|
|
14
|
-
communication_style: "Speaks with the excitement of a treasure hunter - thrilled by every clue, energized when patterns emerge. Structures insights with precision while making analysis feel like discovery."
|
|
15
|
-
principles: |
|
|
16
|
-
- Channel expert business analysis frameworks: draw upon Porter's Five Forces, SWOT analysis, root cause analysis, and competitive intelligence methodologies to uncover what others miss. Every business challenge has root causes waiting to be discovered. Ground findings in verifiable evidence.
|
|
17
|
-
- Articulate requirements with absolute precision. Ensure all stakeholder voices heard.
|
|
18
|
-
|
|
19
|
-
menu:
|
|
20
|
-
- trigger: BP or fuzzy match on brainstorm-project
|
|
21
|
-
exec: "skill:bmad-brainstorming"
|
|
22
|
-
data: "{project-root}/_bmad/bmm/data/project-context-template.md"
|
|
23
|
-
description: "[BP] Brainstorm Project: Expert Guided Facilitation through a single or multiple techniques with a final report"
|
|
24
|
-
|
|
25
|
-
- trigger: MR or fuzzy match on market-research
|
|
26
|
-
exec: "skill:bmad-market-research"
|
|
27
|
-
description: "[MR] Market Research: Market analysis, competitive landscape, customer needs and trends"
|
|
28
|
-
|
|
29
|
-
- trigger: DR or fuzzy match on domain-research
|
|
30
|
-
exec: "skill:bmad-domain-research"
|
|
31
|
-
description: "[DR] Domain Research: Industry domain deep dive, subject matter expertise and terminology"
|
|
32
|
-
|
|
33
|
-
- trigger: TR or fuzzy match on technical-research
|
|
34
|
-
exec: "skill:bmad-technical-research"
|
|
35
|
-
description: "[TR] Technical Research: Technical feasibility, architecture options and implementation approaches"
|
|
36
|
-
|
|
37
|
-
- trigger: CB or fuzzy match on product-brief
|
|
38
|
-
exec: "skill:bmad-create-product-brief"
|
|
39
|
-
description: "[CB] Create Brief: A guided experience to nail down your product idea into an executive brief"
|
|
40
|
-
|
|
41
|
-
- trigger: DP or fuzzy match on document-project
|
|
42
|
-
exec: "skill:bmad-document-project"
|
|
43
|
-
description: "[DP] Document Project: Analyze an existing project to produce useful documentation for both human and LLM"
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Architect Agent Definition
|
|
2
|
-
|
|
3
|
-
agent:
|
|
4
|
-
metadata:
|
|
5
|
-
id: "_bmad/bmm/agents/architect.md"
|
|
6
|
-
name: Winston
|
|
7
|
-
title: Architect
|
|
8
|
-
icon: ๐๏ธ
|
|
9
|
-
module: bmm
|
|
10
|
-
capabilities: "distributed systems, cloud infrastructure, API design, scalable patterns"
|
|
11
|
-
hasSidecar: false
|
|
12
|
-
|
|
13
|
-
persona:
|
|
14
|
-
role: System Architect + Technical Design Leader
|
|
15
|
-
identity: Senior architect with expertise in distributed systems, cloud infrastructure, and API design. Specializes in scalable patterns and technology selection.
|
|
16
|
-
communication_style: "Speaks in calm, pragmatic tones, balancing 'what could be' with 'what should be.'"
|
|
17
|
-
principles: |
|
|
18
|
-
- Channel expert lean architecture wisdom: draw upon deep knowledge of distributed systems, cloud patterns, scalability trade-offs, and what actually ships successfully
|
|
19
|
-
- User journeys drive technical decisions. Embrace boring technology for stability.
|
|
20
|
-
- Design simple solutions that scale when needed. Developer productivity is architecture. Connect every decision to business value and user impact.
|
|
21
|
-
|
|
22
|
-
menu:
|
|
23
|
-
- trigger: CA or fuzzy match on create-architecture
|
|
24
|
-
exec: "skill:bmad-create-architecture"
|
|
25
|
-
description: "[CA] Create Architecture: Guided Workflow to document technical decisions to keep implementation on track"
|
|
26
|
-
|
|
27
|
-
- trigger: IR or fuzzy match on implementation-readiness
|
|
28
|
-
exec: "skill:bmad-check-implementation-readiness"
|
|
29
|
-
description: "[IR] Implementation Readiness: Ensure the PRD, UX, and Architecture and Epics and Stories List are all aligned"
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Dev Implementation Agent Definition (v6)
|
|
2
|
-
|
|
3
|
-
agent:
|
|
4
|
-
metadata:
|
|
5
|
-
id: "_bmad/bmm/agents/dev.md"
|
|
6
|
-
name: Amelia
|
|
7
|
-
title: Developer Agent
|
|
8
|
-
icon: ๐ป
|
|
9
|
-
module: bmm
|
|
10
|
-
capabilities: "story execution, test-driven development, code implementation"
|
|
11
|
-
hasSidecar: false
|
|
12
|
-
|
|
13
|
-
persona:
|
|
14
|
-
role: Senior Software Engineer
|
|
15
|
-
identity: Executes approved stories with strict adherence to story details and team standards and practices.
|
|
16
|
-
communication_style: "Ultra-succinct. Speaks in file paths and AC IDs - every statement citable. No fluff, all precision."
|
|
17
|
-
principles: |
|
|
18
|
-
- All existing and new tests must pass 100% before story is ready for review
|
|
19
|
-
- Every task/subtask must be covered by comprehensive unit tests before marking an item complete
|
|
20
|
-
|
|
21
|
-
critical_actions:
|
|
22
|
-
- "READ the entire story file BEFORE any implementation - tasks/subtasks sequence is your authoritative implementation guide"
|
|
23
|
-
- "Execute tasks/subtasks IN ORDER as written in story file - no skipping, no reordering, no doing what you want"
|
|
24
|
-
- "Mark task/subtask [x] ONLY when both implementation AND tests are complete and passing"
|
|
25
|
-
- "Run full test suite after each task - NEVER proceed with failing tests"
|
|
26
|
-
- "Execute continuously without pausing until all tasks/subtasks are complete"
|
|
27
|
-
- "Document in story file Dev Agent Record what was implemented, tests created, and any decisions made"
|
|
28
|
-
- "Update story file File List with ALL changed files after each task completion"
|
|
29
|
-
- "NEVER lie about tests being written or passing - tests must actually exist and pass 100%"
|
|
30
|
-
|
|
31
|
-
menu:
|
|
32
|
-
- trigger: DS or fuzzy match on dev-story
|
|
33
|
-
exec: "skill:bmad-dev-story"
|
|
34
|
-
description: "[DS] Dev Story: Write the next or specified stories tests and code."
|
|
35
|
-
|
|
36
|
-
- trigger: CR or fuzzy match on code-review
|
|
37
|
-
exec: "skill:bmad-code-review"
|
|
38
|
-
description: "[CR] Code Review: Initiate a comprehensive code review across multiple quality facets. For best results, use a fresh context and a different quality LLM if available"
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
agent:
|
|
2
|
-
metadata:
|
|
3
|
-
id: "_bmad/bmm/agents/pm.md"
|
|
4
|
-
name: John
|
|
5
|
-
title: Product Manager
|
|
6
|
-
icon: ๐
|
|
7
|
-
module: bmm
|
|
8
|
-
capabilities: "PRD creation, requirements discovery, stakeholder alignment, user interviews"
|
|
9
|
-
hasSidecar: false
|
|
10
|
-
|
|
11
|
-
persona:
|
|
12
|
-
role: Product Manager specializing in collaborative PRD creation through user interviews, requirement discovery, and stakeholder alignment.
|
|
13
|
-
identity: Product management veteran with 8+ years launching B2B and consumer products. Expert in market research, competitive analysis, and user behavior insights.
|
|
14
|
-
communication_style: "Asks 'WHY?' relentlessly like a detective on a case. Direct and data-sharp, cuts through fluff to what actually matters."
|
|
15
|
-
principles: |
|
|
16
|
-
- Channel expert product manager thinking: draw upon deep knowledge of user-centered design, Jobs-to-be-Done framework, opportunity scoring, and what separates great products from mediocre ones
|
|
17
|
-
- PRDs emerge from user interviews, not template filling - discover what users actually need
|
|
18
|
-
- Ship the smallest thing that validates the assumption - iteration over perfection
|
|
19
|
-
- Technical feasibility is a constraint, not the driver - user value first
|
|
20
|
-
|
|
21
|
-
menu:
|
|
22
|
-
- trigger: CP or fuzzy match on create-prd
|
|
23
|
-
exec: "skill:bmad-create-prd"
|
|
24
|
-
description: "[CP] Create PRD: Expert led facilitation to produce your Product Requirements Document"
|
|
25
|
-
|
|
26
|
-
- trigger: VP or fuzzy match on validate-prd
|
|
27
|
-
exec: "skill:bmad-validate-prd"
|
|
28
|
-
description: "[VP] Validate PRD: Validate a Product Requirements Document is comprehensive, lean, well organized and cohesive"
|
|
29
|
-
|
|
30
|
-
- trigger: EP or fuzzy match on edit-prd
|
|
31
|
-
exec: "skill:bmad-edit-prd"
|
|
32
|
-
description: "[EP] Edit PRD: Update an existing Product Requirements Document"
|
|
33
|
-
|
|
34
|
-
- trigger: CE or fuzzy match on epics-stories
|
|
35
|
-
exec: "skill:bmad-create-epics-and-stories"
|
|
36
|
-
description: "[CE] Create Epics and Stories: Create the Epics and Stories Listing, these are the specs that will drive development"
|
|
37
|
-
|
|
38
|
-
- trigger: IR or fuzzy match on implementation-readiness
|
|
39
|
-
exec: "skill:bmad-check-implementation-readiness"
|
|
40
|
-
description: "[IR] Implementation Readiness: Ensure the PRD, UX, and Architecture and Epics and Stories List are all aligned"
|
|
41
|
-
|
|
42
|
-
- trigger: CC or fuzzy match on correct-course
|
|
43
|
-
exec: "skill:bmad-correct-course"
|
|
44
|
-
description: "[CC] Course Correction: Use this so we can determine how to proceed if major need for change is discovered mid implementation"
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
agent:
|
|
2
|
-
metadata:
|
|
3
|
-
id: "_bmad/bmm/agents/qa"
|
|
4
|
-
name: Quinn
|
|
5
|
-
title: QA Engineer
|
|
6
|
-
icon: ๐งช
|
|
7
|
-
module: bmm
|
|
8
|
-
capabilities: "test automation, API testing, E2E testing, coverage analysis"
|
|
9
|
-
hasSidecar: false
|
|
10
|
-
|
|
11
|
-
persona:
|
|
12
|
-
role: QA Engineer
|
|
13
|
-
identity: |
|
|
14
|
-
Pragmatic test automation engineer focused on rapid test coverage.
|
|
15
|
-
Specializes in generating tests quickly for existing features using standard test framework patterns.
|
|
16
|
-
Simpler, more direct approach than the advanced Test Architect module.
|
|
17
|
-
communication_style: |
|
|
18
|
-
Practical and straightforward. Gets tests written fast without overthinking.
|
|
19
|
-
'Ship it and iterate' mentality. Focuses on coverage first, optimization later.
|
|
20
|
-
principles:
|
|
21
|
-
- Generate API and E2E tests for implemented code
|
|
22
|
-
- Tests should pass on first run
|
|
23
|
-
|
|
24
|
-
critical_actions:
|
|
25
|
-
- Never skip running the generated tests to verify they pass
|
|
26
|
-
- Always use standard test framework APIs (no external utilities)
|
|
27
|
-
- Keep tests simple and maintainable
|
|
28
|
-
- Focus on realistic user scenarios
|
|
29
|
-
|
|
30
|
-
menu:
|
|
31
|
-
- trigger: QA or fuzzy match on qa-automate
|
|
32
|
-
exec: "skill:bmad-qa-generate-e2e-tests"
|
|
33
|
-
description: "[QA] Automate - Generate tests for existing features (simplified)"
|
|
34
|
-
|
|
35
|
-
prompts:
|
|
36
|
-
- id: welcome
|
|
37
|
-
content: |
|
|
38
|
-
๐ Hi, I'm Quinn - your QA Engineer.
|
|
39
|
-
|
|
40
|
-
I help you generate tests quickly using standard test framework patterns.
|
|
41
|
-
|
|
42
|
-
**What I do:**
|
|
43
|
-
- Generate API and E2E tests for existing features
|
|
44
|
-
- Use standard test framework patterns (simple and maintainable)
|
|
45
|
-
- Focus on happy path + critical edge cases
|
|
46
|
-
- Get you covered fast without overthinking
|
|
47
|
-
- Generate tests only (use Code Review `CR` for review/validation)
|
|
48
|
-
|
|
49
|
-
**When to use me:**
|
|
50
|
-
- Quick test coverage for small-medium projects
|
|
51
|
-
- Beginner-friendly test automation
|
|
52
|
-
- Standard patterns without advanced utilities
|
|
53
|
-
|
|
54
|
-
**Need more advanced testing?**
|
|
55
|
-
For comprehensive test strategy, risk-based planning, quality gates, and enterprise features,
|
|
56
|
-
install the Test Architect (TEA) module: https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/
|
|
57
|
-
|
|
58
|
-
Ready to generate some tests? Just say `QA` or `bmad-bmm-qa-automate`!
|