Compare commits
7 Commits
e797e6efe0
...
8c6ed44c11
| Author | SHA1 | Date |
|---|---|---|
|
|
8c6ed44c11 | |
|
|
d401afd3f3 | |
|
|
b4d6a92e65 | |
|
|
246270bef2 | |
|
|
79a6876a65 | |
|
|
83f374c254 | |
|
|
1a85069b75 |
|
|
@ -1,5 +1,6 @@
|
||||||
code: core
|
code: core
|
||||||
name: "BMad Core Module"
|
name: "BMad Core Module"
|
||||||
|
description: "Core configuration and shared resources"
|
||||||
|
|
||||||
header: "BMad Core Configuration"
|
header: "BMad Core Configuration"
|
||||||
subheader: "Configure the core settings for your BMad installation.\nThese settings will be used across all installed bmad skills, workflows, and agents."
|
subheader: "Configure the core settings for your BMad installation.\nThese settings will be used across all installed bmad skills, workflows, and agents."
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
name: validate-workflow
|
||||||
|
description: "Run a checklist against a document with thorough analysis and produce a validation report"
|
||||||
|
---
|
||||||
|
|
||||||
|
Follow the instructions in [workflow.md](workflow.md).
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
type: skill
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Validate Workflow Output
|
||||||
|
|
||||||
|
**Goal:** Run a checklist against a document with thorough analysis and produce a validation report.
|
||||||
|
|
||||||
|
**Inputs:**
|
||||||
|
|
||||||
|
- **workflow** (required) — Workflow path containing `checklist.md`
|
||||||
|
- **checklist** (optional) — Checklist to validate against (defaults to the workflow's `checklist.md`)
|
||||||
|
- **document** (optional) — Document to validate (ask user if not specified)
|
||||||
|
|
||||||
|
## STEPS
|
||||||
|
|
||||||
|
### Step 1: Setup
|
||||||
|
|
||||||
|
- If checklist not provided, load `checklist.md` from the workflow location
|
||||||
|
- Try to fuzzy-match files similar to the input document name; if document not provided or unsure, ask user: "Which document should I validate?"
|
||||||
|
- Load both the checklist and document
|
||||||
|
|
||||||
|
### Step 2: Validate (CRITICAL)
|
||||||
|
|
||||||
|
**For EVERY checklist item, WITHOUT SKIPPING ANY:**
|
||||||
|
|
||||||
|
1. Read the requirement carefully
|
||||||
|
2. Search the document for evidence along with any ancillary loaded documents or artifacts (quotes with line numbers)
|
||||||
|
3. Analyze deeply — look for explicit AND implied coverage
|
||||||
|
|
||||||
|
**Mark each item as:**
|
||||||
|
|
||||||
|
- **PASS** `✓` — Requirement fully met (provide evidence)
|
||||||
|
- **PARTIAL** `⚠` — Some coverage but incomplete (explain gaps)
|
||||||
|
- **FAIL** `✗` — Not met or severely deficient (explain why)
|
||||||
|
- **N/A** `➖` — Not applicable (explain reason)
|
||||||
|
|
||||||
|
**DO NOT SKIP ANY SECTIONS OR ITEMS.**
|
||||||
|
|
||||||
|
### Step 3: Generate Report
|
||||||
|
|
||||||
|
Create `validation-report-{timestamp}.md` in the document's folder with the following format:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Validation Report
|
||||||
|
|
||||||
|
**Document:** {document-path}
|
||||||
|
**Checklist:** {checklist-path}
|
||||||
|
**Date:** {timestamp}
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
- Overall: X/Y passed (Z%)
|
||||||
|
- Critical Issues: {count}
|
||||||
|
|
||||||
|
## Section Results
|
||||||
|
|
||||||
|
### {Section Name}
|
||||||
|
|
||||||
|
Pass Rate: X/Y (Z%)
|
||||||
|
|
||||||
|
[MARK] {Item description}
|
||||||
|
Evidence: {Quote with line# or explanation}
|
||||||
|
{If FAIL/PARTIAL: Impact: {why this matters}}
|
||||||
|
|
||||||
|
## Failed Items
|
||||||
|
|
||||||
|
{All ✗ items with recommendations}
|
||||||
|
|
||||||
|
## Partial Items
|
||||||
|
|
||||||
|
{All ⚠ items with what's missing}
|
||||||
|
|
||||||
|
## Recommendations
|
||||||
|
|
||||||
|
1. Must Fix: {critical failures}
|
||||||
|
2. Should Improve: {important gaps}
|
||||||
|
3. Consider: {minor improvements}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Summary for User
|
||||||
|
|
||||||
|
- Present section-by-section summary
|
||||||
|
- Highlight all critical issues
|
||||||
|
- Provide path to saved report
|
||||||
|
- **HALT** — do not continue unless user asks
|
||||||
|
|
||||||
|
## HALT CONDITIONS
|
||||||
|
|
||||||
|
- HALT after presenting summary in Step 4
|
||||||
|
- HALT with error if no checklist is found and none is provided
|
||||||
|
- HALT with error if no document is found and user does not specify one
|
||||||
|
|
@ -598,7 +598,7 @@ class UI {
|
||||||
const officialCodes = new Set(officialSelected);
|
const officialCodes = new Set(officialSelected);
|
||||||
const externalManager = new ExternalModuleManager();
|
const externalManager = new ExternalModuleManager();
|
||||||
const registryModules = await externalManager.listAvailable();
|
const registryModules = await externalManager.listAvailable();
|
||||||
const officialRegistryCodes = new Set(registryModules.map((m) => m.code));
|
const officialRegistryCodes = new Set(['core', 'bmm', ...registryModules.map((m) => m.code)]);
|
||||||
const installedNonOfficial = [...installedModuleIds].filter((id) => !officialRegistryCodes.has(id));
|
const installedNonOfficial = [...installedModuleIds].filter((id) => !officialRegistryCodes.has(id));
|
||||||
|
|
||||||
// Phase 2: Community modules (category drill-down)
|
// Phase 2: Community modules (category drill-down)
|
||||||
|
|
@ -630,6 +630,11 @@ class UI {
|
||||||
* @returns {Array} Selected official module codes
|
* @returns {Array} Selected official module codes
|
||||||
*/
|
*/
|
||||||
async _selectOfficialModules(installedModuleIds = new Set()) {
|
async _selectOfficialModules(installedModuleIds = new Set()) {
|
||||||
|
// Built-in modules (core, bmm) come from local source, not the registry
|
||||||
|
const { OfficialModules } = require('./modules/official-modules');
|
||||||
|
const builtInModules = (await new OfficialModules().listAvailable()).modules || [];
|
||||||
|
|
||||||
|
// External modules come from the registry (with fallback)
|
||||||
const externalManager = new ExternalModuleManager();
|
const externalManager = new ExternalModuleManager();
|
||||||
const registryModules = await externalManager.listAvailable();
|
const registryModules = await externalManager.listAvailable();
|
||||||
|
|
||||||
|
|
@ -637,20 +642,34 @@ class UI {
|
||||||
const initialValues = [];
|
const initialValues = [];
|
||||||
const lockedValues = ['core'];
|
const lockedValues = ['core'];
|
||||||
|
|
||||||
const buildModuleEntry = async (mod) => {
|
const buildModuleEntry = async (code, name, description, isDefault) => {
|
||||||
const isInstalled = installedModuleIds.has(mod.code);
|
const isInstalled = installedModuleIds.has(code);
|
||||||
const version = await getMarketplaceVersion(mod.code);
|
const version = await getMarketplaceVersion(code);
|
||||||
const label = version ? `${mod.name} (v${version})` : mod.name;
|
const label = version ? `${name} (v${version})` : name;
|
||||||
return {
|
return {
|
||||||
label,
|
label,
|
||||||
value: mod.code,
|
value: code,
|
||||||
hint: mod.description,
|
hint: description,
|
||||||
selected: isInstalled,
|
selected: isInstalled || isDefault,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add built-in modules first (always available regardless of network)
|
||||||
|
const builtInCodes = new Set();
|
||||||
|
for (const mod of builtInModules) {
|
||||||
|
const code = mod.id;
|
||||||
|
builtInCodes.add(code);
|
||||||
|
const entry = await buildModuleEntry(code, mod.name, mod.description, mod.defaultSelected);
|
||||||
|
allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint });
|
||||||
|
if (entry.selected) {
|
||||||
|
initialValues.push(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add external registry modules (skip built-in duplicates)
|
||||||
for (const mod of registryModules) {
|
for (const mod of registryModules) {
|
||||||
const entry = await buildModuleEntry(mod);
|
if (mod.builtIn || builtInCodes.has(mod.code)) continue;
|
||||||
|
const entry = await buildModuleEntry(mod.code, mod.name, mod.description, mod.defaultSelected);
|
||||||
allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint });
|
allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint });
|
||||||
if (entry.selected) {
|
if (entry.selected) {
|
||||||
initialValues.push(mod.code);
|
initialValues.push(mod.code);
|
||||||
|
|
@ -1122,12 +1141,26 @@ class UI {
|
||||||
* @returns {Array} Default module codes
|
* @returns {Array} Default module codes
|
||||||
*/
|
*/
|
||||||
async getDefaultModules(installedModuleIds = new Set()) {
|
async getDefaultModules(installedModuleIds = new Set()) {
|
||||||
|
// Built-in modules with default_selected come from local source
|
||||||
|
const { OfficialModules } = require('./modules/official-modules');
|
||||||
|
const builtInModules = (await new OfficialModules().listAvailable()).modules || [];
|
||||||
|
|
||||||
|
const defaultModules = [];
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
for (const mod of builtInModules) {
|
||||||
|
if (mod.defaultSelected || installedModuleIds.has(mod.id)) {
|
||||||
|
defaultModules.push(mod.id);
|
||||||
|
seen.add(mod.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add external registry defaults
|
||||||
const externalManager = new ExternalModuleManager();
|
const externalManager = new ExternalModuleManager();
|
||||||
const registryModules = await externalManager.listAvailable();
|
const registryModules = await externalManager.listAvailable();
|
||||||
|
|
||||||
const defaultModules = [];
|
|
||||||
|
|
||||||
for (const mod of registryModules) {
|
for (const mod of registryModules) {
|
||||||
|
if (mod.builtIn || seen.has(mod.code)) continue;
|
||||||
if (mod.defaultSelected || installedModuleIds.has(mod.code)) {
|
if (mod.defaultSelected || installedModuleIds.has(mod.code)) {
|
||||||
defaultModules.push(mod.code);
|
defaultModules.push(mod.code);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@
|
||||||
.agent-icon.john { background: linear-gradient(135deg, #60a5fa, #3b82f6); }
|
.agent-icon.john { background: linear-gradient(135deg, #60a5fa, #3b82f6); }
|
||||||
.agent-icon.sally { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #000; }
|
.agent-icon.sally { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #000; }
|
||||||
.agent-icon.winston { background: linear-gradient(135deg, #a78bfa, #8b5cf6); }
|
.agent-icon.winston { background: linear-gradient(135deg, #a78bfa, #8b5cf6); }
|
||||||
.agent-icon.bob { background: linear-gradient(135deg, #34d399, #10b981); color: #000; }
|
|
||||||
.agent-icon.amelia { background: linear-gradient(135deg, #fb7185, #ef4444); }
|
.agent-icon.amelia { background: linear-gradient(135deg, #fb7185, #ef4444); }
|
||||||
|
|
||||||
.agent-name { font-size: 0.65rem; }
|
.agent-name { font-size: 0.65rem; }
|
||||||
|
|
@ -261,7 +260,7 @@
|
||||||
<span class="workflow-name">sprint-planning</span>
|
<span class="workflow-name">sprint-planning</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent"><div class="agent-icon bob">B</div><span class="agent-name">Bob</span></div>
|
<div class="agent"><div class="agent-icon amelia">A</div><span class="agent-name">Amelia</span></div>
|
||||||
<span class="output">sprint-status.yaml →</span>
|
<span class="output">sprint-status.yaml →</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -270,7 +269,7 @@
|
||||||
<span class="workflow-name">create-story</span>
|
<span class="workflow-name">create-story</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent"><div class="agent-icon bob">B</div><span class="agent-name">Bob</span></div>
|
<div class="agent"><div class="agent-icon amelia">A</div><span class="agent-name">Amelia</span></div>
|
||||||
<span class="output">story-[slug].md →</span>
|
<span class="output">story-[slug].md →</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -308,7 +307,7 @@
|
||||||
<span class="badge adhoc">par Epic</span>
|
<span class="badge adhoc">par Epic</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent"><div class="agent-icon bob">B</div><span class="agent-name">Bob</span></div>
|
<div class="agent"><div class="agent-icon amelia">A</div><span class="agent-name">Amelia</span></div>
|
||||||
<span class="output">leçons</span>
|
<span class="output">leçons</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@
|
||||||
.agent-icon.john { background: linear-gradient(135deg, #60a5fa, #3b82f6); }
|
.agent-icon.john { background: linear-gradient(135deg, #60a5fa, #3b82f6); }
|
||||||
.agent-icon.sally { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #000; }
|
.agent-icon.sally { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #000; }
|
||||||
.agent-icon.winston { background: linear-gradient(135deg, #a78bfa, #8b5cf6); }
|
.agent-icon.winston { background: linear-gradient(135deg, #a78bfa, #8b5cf6); }
|
||||||
.agent-icon.bob { background: linear-gradient(135deg, #34d399, #10b981); color: #000; }
|
|
||||||
.agent-icon.amelia { background: linear-gradient(135deg, #fb7185, #ef4444); }
|
.agent-icon.amelia { background: linear-gradient(135deg, #fb7185, #ef4444); }
|
||||||
|
|
||||||
.agent-name { font-size: 0.65rem; }
|
.agent-name { font-size: 0.65rem; }
|
||||||
|
|
@ -272,7 +271,7 @@
|
||||||
<span class="workflow-name">sprint-planning</span>
|
<span class="workflow-name">sprint-planning</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent"><div class="agent-icon bob">B</div><span class="agent-name">Bob</span></div>
|
<div class="agent"><div class="agent-icon amelia">A</div><span class="agent-name">Amelia</span></div>
|
||||||
<span class="output">sprint-status.yaml →</span>
|
<span class="output">sprint-status.yaml →</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -281,7 +280,7 @@
|
||||||
<span class="workflow-name">create-story</span>
|
<span class="workflow-name">create-story</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent"><div class="agent-icon bob">B</div><span class="agent-name">Bob</span></div>
|
<div class="agent"><div class="agent-icon amelia">A</div><span class="agent-name">Amelia</span></div>
|
||||||
<span class="output">story-[slug].md →</span>
|
<span class="output">story-[slug].md →</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -319,7 +318,7 @@
|
||||||
<span class="badge adhoc">per epic</span>
|
<span class="badge adhoc">per epic</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-meta">
|
<div class="workflow-meta">
|
||||||
<div class="agent"><div class="agent-icon bob">B</div><span class="agent-name">Bob</span></div>
|
<div class="agent"><div class="agent-icon amelia">A</div><span class="agent-name">Amelia</span></div>
|
||||||
<span class="output">lessons</span>
|
<span class="output">lessons</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue