bmad-method 6.2.3-next.11 → 6.2.3-next.13
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-plugin/marketplace.json +0 -1
- package/package.json +1 -1
- package/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md +1 -0
- package/tools/installer/core/installer.js +6 -53
- package/tools/installer/core/manifest-generator.js +9 -0
- package/tools/installer/modules/custom-modules.js +105 -0
- package/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/SKILL.md +0 -53
- package/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml +0 -11
|
@@ -61,7 +61,6 @@
|
|
|
61
61
|
"./src/bmm-skills/4-implementation/bmad-agent-dev",
|
|
62
62
|
"./src/bmm-skills/4-implementation/bmad-agent-sm",
|
|
63
63
|
"./src/bmm-skills/4-implementation/bmad-agent-qa",
|
|
64
|
-
"./src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev",
|
|
65
64
|
"./src/bmm-skills/4-implementation/bmad-dev-story",
|
|
66
65
|
"./src/bmm-skills/4-implementation/bmad-quick-dev",
|
|
67
66
|
"./src/bmm-skills/4-implementation/bmad-sprint-planning",
|
package/package.json
CHANGED
|
@@ -42,6 +42,7 @@ When you are in this persona and the user calls a skill, this persona must carry
|
|
|
42
42
|
| Code | Description | Skill |
|
|
43
43
|
|------|-------------|-------|
|
|
44
44
|
| DS | Write the next or specified story's tests and code | bmad-dev-story |
|
|
45
|
+
| QD | Unified quick flow — clarify intent, plan, implement, review, present | bmad-quick-dev |
|
|
45
46
|
| CR | Initiate a comprehensive code review across multiple quality facets | bmad-code-review |
|
|
46
47
|
|
|
47
48
|
## On Activation
|
|
@@ -1144,59 +1144,12 @@ class Installer {
|
|
|
1144
1144
|
const configuredIdes = existingInstall.ides;
|
|
1145
1145
|
const projectRoot = path.dirname(bmadDir);
|
|
1146
1146
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
id: source.id,
|
|
1154
|
-
name: source.name || source.id,
|
|
1155
|
-
sourcePath: source.path,
|
|
1156
|
-
cached: false, // From CLI, will be re-cached
|
|
1157
|
-
});
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
1162
|
-
if (await fs.pathExists(cacheDir)) {
|
|
1163
|
-
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
1164
|
-
|
|
1165
|
-
for (const cachedModule of cachedModules) {
|
|
1166
|
-
const moduleId = cachedModule.name;
|
|
1167
|
-
const cachedPath = path.join(cacheDir, moduleId);
|
|
1168
|
-
|
|
1169
|
-
// Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT
|
|
1170
|
-
if (!(await fs.pathExists(cachedPath))) {
|
|
1171
|
-
continue;
|
|
1172
|
-
}
|
|
1173
|
-
if (!cachedModule.isDirectory()) {
|
|
1174
|
-
continue;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
// Skip if we already have this module from manifest
|
|
1178
|
-
if (customModuleSources.has(moduleId)) {
|
|
1179
|
-
continue;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
// Check if this is an external official module - skip cache for those
|
|
1183
|
-
const isExternal = await this.externalModuleManager.hasModule(moduleId);
|
|
1184
|
-
if (isExternal) {
|
|
1185
|
-
continue;
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
// Check if this is actually a custom module (has module.yaml)
|
|
1189
|
-
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
|
1190
|
-
if (await fs.pathExists(moduleYamlPath)) {
|
|
1191
|
-
customModuleSources.set(moduleId, {
|
|
1192
|
-
id: moduleId,
|
|
1193
|
-
name: moduleId,
|
|
1194
|
-
sourcePath: cachedPath,
|
|
1195
|
-
cached: true,
|
|
1196
|
-
});
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1147
|
+
const customModuleSources = await this.customModules.assembleQuickUpdateSources(
|
|
1148
|
+
config,
|
|
1149
|
+
existingInstall,
|
|
1150
|
+
bmadDir,
|
|
1151
|
+
this.externalModuleManager,
|
|
1152
|
+
);
|
|
1200
1153
|
|
|
1201
1154
|
// Get available modules (what we have source for)
|
|
1202
1155
|
const availableModulesData = await new OfficialModules().listAvailable();
|
|
@@ -377,10 +377,12 @@ class ManifestGenerator {
|
|
|
377
377
|
*/
|
|
378
378
|
async writeMainManifest(cfgDir) {
|
|
379
379
|
const manifestPath = path.join(cfgDir, 'manifest.yaml');
|
|
380
|
+
const installedModuleSet = new Set(this.modules);
|
|
380
381
|
|
|
381
382
|
// Read existing manifest to preserve install date
|
|
382
383
|
let existingInstallDate = null;
|
|
383
384
|
const existingModulesMap = new Map();
|
|
385
|
+
let existingCustomModules = [];
|
|
384
386
|
|
|
385
387
|
if (await fs.pathExists(manifestPath)) {
|
|
386
388
|
try {
|
|
@@ -402,6 +404,12 @@ class ManifestGenerator {
|
|
|
402
404
|
}
|
|
403
405
|
}
|
|
404
406
|
}
|
|
407
|
+
|
|
408
|
+
if (existingManifest.customModules && Array.isArray(existingManifest.customModules)) {
|
|
409
|
+
// We filter here so manifest regeneration preserves source metadata only for custom modules that
|
|
410
|
+
// are still installed. Without that, customModules can retain stale entries for modules that were removed.
|
|
411
|
+
existingCustomModules = existingManifest.customModules.filter((customModule) => installedModuleSet.has(customModule?.id));
|
|
412
|
+
}
|
|
405
413
|
} catch {
|
|
406
414
|
// If we can't read existing manifest, continue with defaults
|
|
407
415
|
}
|
|
@@ -437,6 +445,7 @@ class ManifestGenerator {
|
|
|
437
445
|
lastUpdated: new Date().toISOString(),
|
|
438
446
|
},
|
|
439
447
|
modules: updatedModules,
|
|
448
|
+
customModules: existingCustomModules,
|
|
440
449
|
ides: this.selectedIdes,
|
|
441
450
|
};
|
|
442
451
|
|
|
@@ -192,6 +192,111 @@ class CustomModules {
|
|
|
192
192
|
|
|
193
193
|
return this.paths;
|
|
194
194
|
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Assemble quick-update source candidates before install() hands them to discoverPaths().
|
|
198
|
+
* This exists because discoverPaths() consumes already-prepared quick-update sources,
|
|
199
|
+
* while quickUpdate() still has to build that source map from manifest, explicit inputs,
|
|
200
|
+
* and cache conventions.
|
|
201
|
+
* Precedence: manifest-backed paths, explicit sources override them, then cached modules.
|
|
202
|
+
* @param {Object} config - Quick update configuration
|
|
203
|
+
* @param {Object} existingInstall - Existing installation snapshot
|
|
204
|
+
* @param {string} bmadDir - BMAD directory
|
|
205
|
+
* @param {Object} externalModuleManager - External module manager
|
|
206
|
+
* @returns {Promise<Map<string, Object>>} Map of custom module ID to source info
|
|
207
|
+
*/
|
|
208
|
+
async assembleQuickUpdateSources(config, existingInstall, bmadDir, externalModuleManager) {
|
|
209
|
+
const projectRoot = path.dirname(bmadDir);
|
|
210
|
+
const customModuleSources = new Map();
|
|
211
|
+
|
|
212
|
+
if (existingInstall.customModules) {
|
|
213
|
+
for (const customModule of existingInstall.customModules) {
|
|
214
|
+
// Skip if no ID - can't reliably track or re-cache without it
|
|
215
|
+
if (!customModule?.id) continue;
|
|
216
|
+
|
|
217
|
+
let sourcePath = customModule.sourcePath;
|
|
218
|
+
if (sourcePath && sourcePath.startsWith('_config')) {
|
|
219
|
+
// Paths are relative to BMAD dir, but we want absolute paths for install
|
|
220
|
+
sourcePath = path.join(bmadDir, sourcePath);
|
|
221
|
+
} else if (!sourcePath && customModule.relativePath) {
|
|
222
|
+
// Fall back to relativePath
|
|
223
|
+
sourcePath = path.resolve(projectRoot, customModule.relativePath);
|
|
224
|
+
} else if (sourcePath && !path.isAbsolute(sourcePath)) {
|
|
225
|
+
// If we have a sourcePath but it's not absolute, resolve it relative to project root
|
|
226
|
+
sourcePath = path.resolve(projectRoot, sourcePath);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// If we still don't have a valid source path, skip this module
|
|
230
|
+
if (!sourcePath || !(await fs.pathExists(sourcePath))) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
customModuleSources.set(customModule.id, {
|
|
235
|
+
id: customModule.id,
|
|
236
|
+
name: customModule.name || customModule.id,
|
|
237
|
+
sourcePath,
|
|
238
|
+
relativePath: customModule.relativePath,
|
|
239
|
+
cached: false,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (config.customContent?.sources?.length > 0) {
|
|
245
|
+
for (const source of config.customContent.sources) {
|
|
246
|
+
if (source.id && source.path) {
|
|
247
|
+
customModuleSources.set(source.id, {
|
|
248
|
+
id: source.id,
|
|
249
|
+
name: source.name || source.id,
|
|
250
|
+
sourcePath: source.path,
|
|
251
|
+
cached: false, // From CLI, will be re-cached
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
258
|
+
if (!(await fs.pathExists(cacheDir))) {
|
|
259
|
+
return customModuleSources;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
263
|
+
for (const cachedModule of cachedModules) {
|
|
264
|
+
const moduleId = cachedModule.name;
|
|
265
|
+
const cachedPath = path.join(cacheDir, moduleId);
|
|
266
|
+
|
|
267
|
+
// Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT
|
|
268
|
+
if (!(await fs.pathExists(cachedPath))) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (!cachedModule.isDirectory()) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Skip if we already have this module from manifest
|
|
276
|
+
if (customModuleSources.has(moduleId)) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Check if this is an external official module - skip cache for those
|
|
281
|
+
const isExternal = await externalModuleManager.hasModule(moduleId);
|
|
282
|
+
if (isExternal) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Check if this is actually a custom module (has module.yaml)
|
|
287
|
+
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
|
288
|
+
if (await fs.pathExists(moduleYamlPath)) {
|
|
289
|
+
customModuleSources.set(moduleId, {
|
|
290
|
+
id: moduleId,
|
|
291
|
+
name: moduleId,
|
|
292
|
+
sourcePath: cachedPath,
|
|
293
|
+
cached: true,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return customModuleSources;
|
|
299
|
+
}
|
|
195
300
|
}
|
|
196
301
|
|
|
197
302
|
module.exports = { CustomModules };
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: bmad-agent-quick-flow-solo-dev
|
|
3
|
-
description: Elite full-stack developer for rapid spec and implementation. Use when the user asks to talk to Barry or requests the quick flow solo dev.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Barry
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
This skill provides an Elite Full-Stack Developer who handles Quick Flow — from tech spec creation through implementation. Act as Barry — direct, confident, and implementation-focused. Minimum ceremony, lean artifacts, ruthless efficiency.
|
|
11
|
-
|
|
12
|
-
## Identity
|
|
13
|
-
|
|
14
|
-
Barry handles Quick Flow — from tech spec creation through implementation. Minimum ceremony, lean artifacts, ruthless efficiency.
|
|
15
|
-
|
|
16
|
-
## Communication Style
|
|
17
|
-
|
|
18
|
-
Direct, confident, and implementation-focused. Uses tech slang (e.g., refactor, patch, extract, spike) and gets straight to the point. No fluff, just results. Stays focused on the task at hand.
|
|
19
|
-
|
|
20
|
-
## Principles
|
|
21
|
-
|
|
22
|
-
- Planning and execution are two sides of the same coin.
|
|
23
|
-
- Specs are for building, not bureaucracy. Code that ships is better than perfect code that doesn't.
|
|
24
|
-
|
|
25
|
-
You must fully embody this persona so the user gets the best experience and help they need, therefore its important to remember you must not break character until the users dismisses this persona.
|
|
26
|
-
|
|
27
|
-
When you are in this persona and the user calls a skill, this persona must carry through and remain active.
|
|
28
|
-
|
|
29
|
-
## Capabilities
|
|
30
|
-
|
|
31
|
-
| Code | Description | Skill |
|
|
32
|
-
|------|-------------|-------|
|
|
33
|
-
| QD | Unified quick flow — clarify intent, plan, implement, review, present | bmad-quick-dev |
|
|
34
|
-
| CR | Initiate a comprehensive code review across multiple quality facets | bmad-code-review |
|
|
35
|
-
|
|
36
|
-
## On Activation
|
|
37
|
-
|
|
38
|
-
1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
|
39
|
-
- Use `{user_name}` for greeting
|
|
40
|
-
- Use `{communication_language}` for all communications
|
|
41
|
-
- Use `{document_output_language}` for output documents
|
|
42
|
-
- Use `{planning_artifacts}` for output location and artifact scanning
|
|
43
|
-
- Use `{project_knowledge}` for additional context scanning
|
|
44
|
-
|
|
45
|
-
2. **Continue with steps below:**
|
|
46
|
-
- **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it.
|
|
47
|
-
- **Greet and present capabilities** — Greet `{user_name}` warmly by name, always speaking in `{communication_language}` and applying your persona throughout the session.
|
|
48
|
-
|
|
49
|
-
3. Remind the user they can invoke the `bmad-help` skill at any time for advice and then present the capabilities table from the Capabilities section above.
|
|
50
|
-
|
|
51
|
-
**STOP and WAIT for user input** — Do NOT execute menu items automatically. Accept number, menu code, or fuzzy command match.
|
|
52
|
-
|
|
53
|
-
**CRITICAL Handling:** When user responds with a code, line number or skill, invoke the corresponding skill by its exact registered name from the Capabilities table. DO NOT invent capabilities on the fly.
|
package/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
type: agent
|
|
2
|
-
name: bmad-agent-quick-flow-solo-dev
|
|
3
|
-
displayName: Barry
|
|
4
|
-
title: Quick Flow Solo Dev
|
|
5
|
-
icon: "🚀"
|
|
6
|
-
capabilities: "rapid spec creation, lean implementation, minimum ceremony"
|
|
7
|
-
role: Elite Full-Stack Developer + Quick Flow Specialist
|
|
8
|
-
identity: "Barry handles Quick Flow - from tech spec creation through implementation. Minimum ceremony, lean artifacts, ruthless efficiency."
|
|
9
|
-
communicationStyle: "Direct, confident, and implementation-focused. Uses tech slang (e.g., refactor, patch, extract, spike) and gets straight to the point. No fluff, just results. Stays focused on the task at hand."
|
|
10
|
-
principles: "Planning and execution are two sides of the same coin. Specs are for building, not bureaucracy. Code that ships is better than perfect code that doesn't."
|
|
11
|
-
module: bmm
|