fix: address coderabbit workflow migration follow-ups

This commit is contained in:
Dicky Moore 2026-02-08 22:16:06 +00:00
parent dde139a560
commit 0a3f48f13f
7 changed files with 165 additions and 94 deletions

View File

@ -78,15 +78,15 @@ Work through phases 1-3. **Use fresh chats for each workflow.**
### Phase 1: Analysis (Optional)
All workflows in this phase are optional:
- **brainstorming** — Guided ideation
- **research** — Market and technical research
- **create-product-brief** — Recommended foundation document
- **brainstorming** (`bmad-bmm-brainstorming`) — Guided ideation
- **research** (`bmad-bmm-research`) — Market and technical research
- **create-product-brief** (`bmad-bmm-create-product-brief`) — Recommended foundation document
### Phase 2: Planning (Required)
**For BMad Method and Enterprise tracks:**
1. Load the **PM agent** in a new chat
2. Run the `prd` workflow
2. Run the `create-prd` workflow (`bmad-bmm-create-prd`)
3. Output: `PRD.md`
**For Quick Flow track:**
@ -100,7 +100,7 @@ If your project has a user interface, load the **UX-Designer agent** and run the
**Create Architecture**
1. Load the **Architect agent** in a new chat
2. Run `create-architecture`
2. Run `create-architecture` (`bmad-bmm-create-architecture`)
3. Output: Architecture document with technical decisions
**Create Epics and Stories**
@ -110,12 +110,12 @@ Epics and stories are now created *after* architecture. This produces better qua
:::
1. Load the **PM agent** in a new chat
2. Run `create-epics-and-stories`
2. Run `create-epics-and-stories` (`bmad-bmm-create-epics-and-stories`)
3. The workflow uses both PRD and Architecture to create technically-informed stories
**Implementation Readiness Check** *(Highly Recommended)*
1. Load the **Architect agent** in a new chat
2. Run `check-implementation-readiness`
2. Run `check-implementation-readiness` (`bmad-bmm-check-implementation-readiness`)
3. Validates cohesion across all planning documents
## Step 2: Build Your Project
@ -124,7 +124,7 @@ Once planning is complete, move to implementation. **Each workflow should run in
### Initialize Sprint Planning
Load the **SM agent** and run `sprint-planning`. This creates `sprint-status.yaml` to track all epics and stories.
Load the **SM agent** and run `sprint-planning` (`bmad-bmm-sprint-planning`). This creates `sprint-status.yaml` to track all epics and stories.
### The Build Cycle
@ -132,11 +132,11 @@ For each story, repeat this cycle with fresh chats:
| Step | Agent | Workflow | Purpose |
| ---- | ----- | -------------- | ---------------------------------- |
| 1 | SM | `create-story` | Create story file from epic |
| 2 | DEV | `dev-story` | Implement the story |
| 3 | DEV | `code-review` | Quality validation *(recommended)* |
| 1 | SM | `create-story` (`bmad-bmm-create-story`) | Create story file from epic |
| 2 | DEV | `dev-story` (`bmad-bmm-dev-story`) | Implement the story |
| 3 | DEV | `code-review` (`bmad-bmm-code-review`) | Quality validation *(recommended)* |
After completing all stories in an epic, load the **SM agent** and run `retrospective`.
After completing all stories in an epic, load the **SM agent** and run `retrospective` (`bmad-bmm-retrospective`).
## What You've Accomplished
@ -162,17 +162,17 @@ your-project/
## Quick Reference
| Workflow | Agent | Purpose |
| -------------------------------- | --------- | ------------------------------------ |
| `help` | Any | Get guidance on what to do next |
| `prd` | PM | Create Product Requirements Document |
| `create-architecture` | Architect | Create architecture document |
| `create-epics-and-stories` | PM | Break down PRD into epics |
| `check-implementation-readiness` | Architect | Validate planning cohesion |
| `sprint-planning` | SM | Initialize sprint tracking |
| `create-story` | SM | Create a story file |
| `dev-story` | DEV | Implement a story |
| `code-review` | DEV | Review implemented code |
| Workflow | Slash Command | Agent | Purpose |
| -------------------------------- | ------------------------------------- | --------- | ------------------------------------ |
| `help` | `bmad-help` | Any | Get guidance on what to do next |
| `create-prd` | `bmad-bmm-create-prd` | PM | Create Product Requirements Document |
| `create-architecture` | `bmad-bmm-create-architecture` | Architect | Create architecture document |
| `create-epics-and-stories` | `bmad-bmm-create-epics-and-stories` | PM | Break down PRD into epics |
| `check-implementation-readiness` | `bmad-bmm-check-implementation-readiness` | Architect | Validate planning cohesion |
| `sprint-planning` | `bmad-bmm-sprint-planning` | SM | Initialize sprint tracking |
| `create-story` | `bmad-bmm-create-story` | SM | Create a story file |
| `dev-story` | `bmad-bmm-dev-story` | DEV | Implement a story |
| `code-review` | `bmad-bmm-code-review` | DEV | Review implemented code |
## Common Questions
@ -183,7 +183,7 @@ Only for BMad Method and Enterprise tracks. Quick Flow skips from tech-spec to i
Yes. The SM agent has a `correct-course` workflow for handling scope changes.
**What if I want to brainstorm first?**
Load the Analyst agent and run `brainstorming` before starting your PRD.
Load the Analyst agent and run `brainstorming` (`bmad-bmm-brainstorming`) before starting your PRD.
**Do I need to follow a strict order?**
Not strictly. Once you learn the flow, you can run workflows directly using the Quick Reference above.
@ -192,7 +192,7 @@ Not strictly. Once you learn the flow, you can run workflows directly using the
- **During workflows** — Agents guide you with questions and explanations
- **Community** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues)
- **Stuck?** — Run `help` to see what to do next
- **Stuck?** — Run `help` (`bmad-help` on most platforms) to see what to do next
## Key Takeaways

View File

@ -59,7 +59,7 @@ input_file_patterns:
<check if="{{story_path}} is provided by user or user provided the epic and story number such as 2-4 or 1.6 or epic 1 story 5">
<action>Parse user-provided story path: extract epic_num, story_num, story_title from format like "1-2-user-auth"</action>
<action>Set {{epic_num}}, {{story_num}}, {{story_key}} from user input</action>
<action>GOTO step 2a</action>
<action>GOTO step 2</action>
</check>
<action>Check if {{sprint_status}} file exists for auto discover</action>
@ -85,12 +85,12 @@ input_file_patterns:
<check if="user provides epic-story number">
<action>Parse user input: extract epic_num, story_num, story_title</action>
<action>Set {{epic_num}}, {{story_num}}, {{story_key}} from user input</action>
<action>GOTO step 2a</action>
<action>GOTO step 2</action>
</check>
<check if="user provides story docs path">
<action>Use user-provided path for story documents</action>
<action>GOTO step 2a</action>
<action>GOTO step 2</action>
</check>
</check>
@ -152,7 +152,7 @@ input_file_patterns:
<output>📊 Epic {{epic_num}} status updated to in-progress</output>
</check>
<action>GOTO step 2a</action>
<action>GOTO step 2</action>
</check>
</step>
@ -174,6 +174,7 @@ input_file_patterns:
(As a, I want, so that) - Detailed acceptance criteria (already BDD formatted) - Technical requirements specific to this story -
Business context and value - Success criteria <!-- Previous story analysis for context continuity -->
<check if="story_num > 1">
<action>Set {{previous_story_num}} = {{story_num}} - 1</action>
<action>Load previous story file: {{story_dir}}/{{epic_num}}-{{previous_story_num}}-*.md</action> **PREVIOUS STORY INTELLIGENCE:** -
Dev notes and learnings from previous story - Review feedback and corrections needed - Files that were created/modified and their
patterns - Testing approaches that worked/didn't work - Problems encountered and solutions found - Code patterns established <action>Extract

View File

@ -18,6 +18,13 @@
- Set suggestion = ""
- Set next_workflow = ""
- Set next_agent = ""
- Set status_file_path = ""
- Set field_type = ""
- Set workflow_mode = ""
- Set scan_level = ""
- Set subworkflow_success = false
- Set status_update_success = false
- Set cached_project_types = ""
</action>
<action>Attempt to load workflow status directly from `{output_folder}/bmm-workflow-status.yaml`:
@ -29,10 +36,18 @@
- Extract field_type, warning, suggestion, next_workflow, next_agent if present
- If file is missing, unreadable, or malformed:
- Keep defaults and continue in standalone mode
- Set status_load_error_reason from the caught file/parse error (e.g., missing file, permission denied, YAML parse error)
- Set warning = "Unable to load workflow status from {output_folder}/bmm-workflow-status.yaml: {{status_load_error_reason}}"
- Output warning and continue in standalone mode
</action>
<check if="status_exists == false">
<output>{{suggestion}}</output>
<check if="suggestion != ''">
<output>{{suggestion}}</output>
</check>
<check if="warning != ''">
<output>{{warning}}</output>
</check>
<output>Note: Documentation workflow can run standalone. Continuing without progress tracking.</output>
<action>Set standalone_mode = true</action>
<action>Set status_file_found = false</action>
@ -62,7 +77,9 @@
<output>Note: This may be auto-invoked by prd for brownfield documentation.</output>
<ask>Continue with documentation? (y/n)</ask>
<check if="n">
<output>{{suggestion}}</output>
<check if="suggestion != ''">
<output>{{suggestion}}</output>
</check>
<action>Exit workflow</action>
</check>
</check>
@ -78,14 +95,33 @@
<check if="project-scan-report.json exists">
<action>Read state file and extract: timestamps, mode, scan_level, current_step, completed_steps, project_classification</action>
<action>Validate last_updated from state file:
- If last_updated is missing or invalid, set state_age_hours = 999 and mark state as stale
- Otherwise parse timestamp and continue
</action>
<action>Extract cached project_type_id(s) from state file if present</action>
<action>Calculate age of state file (current time - last_updated)</action>
<check if="state file age >= 24 hours">
<action>Display: "Found old state file (>24 hours). Starting fresh scan."</action>
<action>Create archive directory: {output_folder}/.archive/</action>
<action>Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<action>Attempt to create archive directory: {output_folder}/.archive/</action>
<check if="archive directory creation failed">
<output>Failed to create archive directory at {output_folder}/.archive/. Keeping existing state and exiting to avoid data loss.</output>
<action>Set resume_mode = true</action>
<action>Exit workflow</action>
</check>
<action>Attempt to archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<check if="archive move failed">
<output>Failed to archive old state file. Keeping existing state and exiting to avoid data loss.</output>
<action>Set resume_mode = true</action>
<action>Exit workflow</action>
</check>
<action>Set resume_mode = false</action>
<action>Set workflow_mode = ""</action>
<action>Set scan_level = ""</action>
<action>Set cached_project_types = ""</action>
<action>Set current_step = ""</action>
<action>Set subworkflow_success = false</action>
<action>Continue to Step 3</action>
</check>
@ -112,15 +148,25 @@ Your choice [1/2/3]:
<check if="user selects 1">
<action>Set resume_mode = true</action>
<action>Set workflow_mode = {{mode}}</action>
<action>Validate persisted mode before assigning workflow_mode:
- If mode is one of [deep_dive, initial_scan, full_rescan], set workflow_mode = {{mode}}
- Otherwise set workflow_mode = "full_rescan", set resume_mode = false, and continue as fresh scan
</action>
<action>Set subworkflow_success = false</action>
<action>Load findings summaries from state file</action>
<action>Load cached project_type_id(s) from state file</action>
<critical>CONDITIONAL CSV LOADING FOR RESUME:</critical>
<check if="cached_project_types == ''">
<output>No cached project types found. Falling back to full CSV load.</output>
<action>Load project-types.csv and architecture_registry.csv</action>
<action>Load documentation_requirements_csv for active project classification</action>
</check>
<check if="cached_project_types != ''">
<action>For each cached project_type_id, load ONLY the corresponding row from: {documentation_requirements_csv}</action>
<action>Skip loading project-types.csv and architecture_registry.csv (not needed on resume)</action>
<action>Store loaded doc requirements for use in remaining steps</action>
</check>
<action>Display: "Resuming {{workflow_mode}} from {{current_step}} with cached project type(s): {{cached_project_types}}"</action>
@ -152,9 +198,21 @@ Your choice [1/2/3]:
</check>
<check if="user selects 2">
<action>Create archive directory: {output_folder}/.archive/</action>
<action>Move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<action>Attempt to create archive directory: {output_folder}/.archive/</action>
<check if="archive directory creation failed">
<output>Failed to create archive directory. Keeping existing state and exiting to avoid data loss.</output>
<action>Set resume_mode = true</action>
<action>Exit workflow</action>
</check>
<action>Attempt to move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<check if="archive move failed">
<output>Failed to archive old state file. Keeping existing state and exiting to avoid data loss.</output>
<action>Set resume_mode = true</action>
<action>Exit workflow</action>
</check>
<action>Set resume_mode = false</action>
<action>Reset workflow_mode, scan_level, cached_project_types, current_step to defaults</action>
<action>Set subworkflow_success = false</action>
<action>Continue to Step 3</action>
</check>
@ -198,6 +256,7 @@ Your choice [1/2/3]:
<check if="user selects 1">
<action>Set workflow_mode = "full_rescan"</action>
<action>Set scan_level = "standard"</action>
<action>Display: "Starting full project rescan..."</action>
<action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</action>
<action>Set subworkflow_success = true only if delegated workflow completed without HALT/error</action>
@ -234,6 +293,7 @@ Your choice [1/2/3]:
<check if="index.md does not exist">
<action>Set workflow_mode = "initial_scan"</action>
<action>Set scan_level = "initial"</action>
<action>Display: "No existing documentation found. Starting initial project scan..."</action>
<action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</action>
<action>Set subworkflow_success = true only if delegated workflow completed without HALT/error</action>
@ -282,8 +342,13 @@ Your choice [1/2/3]:
<output>**Status Updated:** Progress tracking updated.
**Next Steps:**
- **Next required:** {{next_workflow}} ({{next_agent}} agent)
- Run `bmad-help` if you need recommended next workflows.</output>
<check if="next_workflow != '' AND next_agent != ''">
<output>- **Next required:** {{next_workflow}} ({{next_agent}} agent)</output>
</check>
<check if="next_workflow == '' OR next_agent == ''">
<output>- **Next required:** not specified</output>
</check>
</check>
<check if="status_file_found == false OR status_update_success != true">

View File

@ -31,7 +31,7 @@ Execute a validation checklist against a target file and report findings clearly
- Path-like tokens in checklist items
- First matching path from glob patterns supplied by checklist/input
- Normalize all candidate paths relative to repo root and resolve `.`/`..`.
- Validate candidate existence and expected file type (`.yaml`, `.yml`, `.json`, or checklist-defined extension).
- Validate candidate existence and expected file type (`.md`, `.yaml`, `.yml`, `.json`, or checklist-defined extension).
- If multiple valid candidates remain, prefer explicit key fields over inferred tokens.
- If no valid candidate is found, prompt user with schema example:
- `Please provide the exact file path (relative to repo root), e.g. ./workflows/ci.yml`
@ -50,11 +50,17 @@ Execute a validation checklist against a target file and report findings clearly
- If checklist requires edits/auto-fixes, follow safe-edit protocol:
- Ask for confirmation before editing.
- Create backup snapshot of target file before changes.
- Use deterministic backup location: `{project-root}/.bmad-tmp/validate-workflow/`.
- Name backup as `{target-file-name}.{timestamp}.bak` and diff as `{target-file-name}.{timestamp}.diff`.
- If temp backup directory cannot be created, fall back to adjacent backup file `{target-file}.bak`.
- Generate reversible diff preview and show it to user.
- Apply edits only after user approval.
- Run syntax/validation checks against edited file.
- If validation fails or user cancels, rollback from backup and report rollback status.
- Record backup/diff locations in task output.
- Record full backup and diff paths in task output.
- Support `retain_artifacts` flag (default `false`) to keep backup/diff artifacts when requested.
6. **Finalize**
- Confirm completion and provide the final validation summary.
- If edits succeeded and `retain_artifacts` is `false`, delete backup/diff artifacts and report cleanup status.
- If edits failed or rollback occurred, preserve backup/diff artifacts and report rollback path explicitly.

View File

@ -114,6 +114,12 @@ async function runTests() {
console.log(`========================================${colors.reset}\n`);
const projectRoot = path.join(__dirname, '..');
const tmpRoots = [];
const trackTmp = async (prefix) => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
tmpRoots.push(dir);
return dir;
};
// ============================================================
// Test 1: YAML → XML Agent Compilation (In-Memory)
@ -432,7 +438,7 @@ async function runTests() {
console.log(`${colors.yellow}Test Suite 11: Gemini Template Extension Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-gemini-install-'));
const tmpRoot = await trackTmp('bmad-gemini-install-');
const projectDir = path.join(tmpRoot, 'project');
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
await fs.ensureDir(projectDir);
@ -470,7 +476,7 @@ async function runTests() {
console.log(`${colors.yellow}Test Suite 12: Manifest Stale Entry Cleanup Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-manifest-clean-'));
const tmpRoot = await trackTmp('bmad-manifest-clean-');
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
await fs.copy(path.join(projectRoot, 'src', 'core'), path.join(bmadDir, 'core'));
await fs.copy(path.join(projectRoot, 'src', 'bmm'), path.join(bmadDir, 'bmm'));
@ -505,7 +511,7 @@ async function runTests() {
console.log(`${colors.yellow}Test Suite 13: Internal Task Exposure Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-task-filter-'));
const tmpRoot = await trackTmp('bmad-task-filter-');
const projectDir = path.join(tmpRoot, 'project');
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
const commandsDir = path.join(tmpRoot, 'commands');
@ -592,7 +598,7 @@ web_bundle:
console.log(`${colors.yellow}Test Suite 16: Task/Tool Standalone + CRLF Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-standalone-crlf-'));
const tmpRoot = await trackTmp('bmad-standalone-crlf-');
const coreTasksDir = path.join(tmpRoot, '_bmad', 'core', 'tasks');
const coreToolsDir = path.join(tmpRoot, '_bmad', 'core', 'tools');
await fs.ensureDir(coreTasksDir);
@ -717,7 +723,7 @@ internal: true
console.log(`${colors.yellow}Test Suite 18: Codex Task Visibility Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-codex-visibility-'));
const tmpRoot = await trackTmp('bmad-codex-visibility-');
const projectDir = path.join(tmpRoot, 'project');
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
await fs.ensureDir(projectDir);
@ -751,7 +757,7 @@ internal: true
console.log(`${colors.yellow}Test Suite 19: Empty Artifact Target Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-empty-target-'));
const tmpRoot = await trackTmp('bmad-empty-target-');
const projectDir = path.join(tmpRoot, 'project');
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
await fs.ensureDir(projectDir);
@ -856,6 +862,10 @@ internal: true
console.log('');
for (const tmpRoot of tmpRoots) {
await fs.remove(tmpRoot).catch(() => {});
}
// ============================================================
// Summary
// ============================================================

View File

@ -75,10 +75,10 @@ class WorkflowCommandGenerator {
if (workflowRelPath.includes('_bmad/')) {
const parts = workflowRelPath.split(/_bmad\//);
if (parts.length > 1) {
workflowRelPath = parts.slice(1).join('/');
workflowRelPath = parts.at(-1);
}
} else if (workflowRelPath.includes('/src/')) {
const match = workflowRelPath.match(/\/src\/([^/]+)\/(.+)/);
} else if (workflowRelPath.includes('/src/') || workflowRelPath.startsWith('src/')) {
const match = workflowRelPath.match(/(?:^|\/)src\/([^/]+)\/(.+)/);
if (match) {
workflowRelPath = `${match[1]}/${match[2]}`;
}
@ -119,30 +119,9 @@ class WorkflowCommandGenerator {
* Generate command content for a workflow
*/
async generateCommandContent(workflow, bmadDir) {
// Determine template based on workflow file type
const templatePath = path.join(path.dirname(this.templatePath), 'workflow-commander.md');
// Load the appropriate template
const template = await fs.readFile(templatePath, 'utf8');
// Convert source path to installed path
// From: /Users/.../src/bmm/workflows/.../workflow.md
// To: {project-root}/_bmad/bmm/workflows/.../workflow.md
let workflowPath = workflow.path;
// Extract the relative path from source
if (workflowPath.includes('/src/bmm/')) {
// bmm is directly under src/
const match = workflowPath.match(/\/src\/bmm\/(.+)/);
if (match) {
workflowPath = `${this.bmadFolderName}/bmm/${match[1]}`;
}
} else if (workflowPath.includes('/src/core/')) {
const match = workflowPath.match(/\/src\/core\/(.+)/);
if (match) {
workflowPath = `${this.bmadFolderName}/core/${match[1]}`;
}
}
// Load the workflow command template
const template = await fs.readFile(this.templatePath, 'utf8');
const workflowPath = this.mapSourcePathToInstalled(workflow.path);
// Replace template variables
return template
@ -212,14 +191,15 @@ class WorkflowCommandGenerator {
When running any workflow:
1. Resolve loader paths:
- Primary: {project-root}/${this.bmadFolderName}/core/tasks/workflow.md
- Fallback: {project-root}/src/core/tasks/workflow.md
- Optional dev fallback: {project-root}/src/core/tasks/workflow.md (only if it exists and is readable)
2. Check the primary path exists and is readable before loading
3. If primary is missing/unreadable, log a warning with the path and error, then try fallback
4. If fallback is also missing/unreadable, log an error with both attempted paths and stop
5. LOAD the resolved workflow loader file
6. Pass the workflow path as 'workflow-config' parameter
7. Follow workflow.md instructions EXACTLY
8. Save outputs after EACH section
3. If primary is missing/unreadable, log a warning with the primary path and error
4. Only if the dev fallback exists and is readable, try the fallback path; otherwise skip it
5. If no readable loader is found, log an error with all attempted readable paths and stop
6. LOAD the resolved workflow loader file
7. Pass the workflow path as 'workflow-config' parameter
8. Follow workflow.md instructions EXACTLY
9. Save outputs after EACH section
## Modes
- Normal: Full interaction
@ -230,21 +210,33 @@ When running any workflow:
}
transformWorkflowPath(workflowPath) {
let transformed = workflowPath;
return this.mapSourcePathToInstalled(workflowPath, true);
}
if (workflowPath.includes('/src/bmm/')) {
const match = workflowPath.match(/\/src\/bmm\/(.+)/);
if (match) {
transformed = `{project-root}/${this.bmadFolderName}/bmm/${match[1]}`;
}
} else if (workflowPath.includes('/src/core/')) {
const match = workflowPath.match(/\/src\/core\/(.+)/);
if (match) {
transformed = `{project-root}/${this.bmadFolderName}/core/${match[1]}`;
}
mapSourcePathToInstalled(sourcePath, includeProjectRootPrefix = false) {
if (!sourcePath) {
return sourcePath;
}
return transformed;
const normalized = sourcePath.replaceAll('\\', '/');
const srcMatch = normalized.match(/(?:^|\/)src\/([^/]+)\/(.+)/);
if (srcMatch) {
const mapped = `${this.bmadFolderName}/${srcMatch[1]}/${srcMatch[2]}`;
return includeProjectRootPrefix ? `{project-root}/${mapped}` : mapped;
}
if (normalized.includes('_bmad/')) {
const parts = normalized.split(/_bmad\//);
const relative = parts.at(-1);
const mapped = `${this.bmadFolderName}/${relative}`;
return includeProjectRootPrefix ? `{project-root}/${mapped}` : mapped;
}
if (normalized.startsWith(`${this.bmadFolderName}/`)) {
return includeProjectRootPrefix ? `{project-root}/${normalized}` : normalized;
}
return sourcePath;
}
async loadWorkflowManifest(bmadDir) {

View File

@ -813,7 +813,6 @@ class ModuleManager {
const newline = frontmatterMatch[0].includes('\r\n') ? '\r\n' : '\n';
try {
const yaml = require('yaml');
const parsed = yaml.parse(frontmatterMatch[1]);
if (!parsed || typeof parsed !== 'object' || !Object.prototype.hasOwnProperty.call(parsed, 'web_bundle')) {
@ -897,7 +896,6 @@ class ModuleManager {
let manifestData = {};
if (await fs.pathExists(manifestPath)) {
const manifestContent = await fs.readFile(manifestPath, 'utf8');
const yaml = require('yaml');
manifestData = yaml.parse(manifestContent);
}
if (!manifestData.agentCustomizations) {
@ -906,7 +904,6 @@ class ModuleManager {
manifestData.agentCustomizations[path.relative(bmadDir, customizePath)] = originalHash;
// Write back to manifest
const yaml = require('yaml');
// Clean the manifest data to remove any non-serializable values
const cleanManifestData = structuredClone(manifestData);