fix: address coderabbit workflow migration follow-ups
This commit is contained in:
parent
dde139a560
commit
0a3f48f13f
|
|
@ -78,15 +78,15 @@ Work through phases 1-3. **Use fresh chats for each workflow.**
|
||||||
### Phase 1: Analysis (Optional)
|
### Phase 1: Analysis (Optional)
|
||||||
|
|
||||||
All workflows in this phase are optional:
|
All workflows in this phase are optional:
|
||||||
- **brainstorming** — Guided ideation
|
- **brainstorming** (`bmad-bmm-brainstorming`) — Guided ideation
|
||||||
- **research** — Market and technical research
|
- **research** (`bmad-bmm-research`) — Market and technical research
|
||||||
- **create-product-brief** — Recommended foundation document
|
- **create-product-brief** (`bmad-bmm-create-product-brief`) — Recommended foundation document
|
||||||
|
|
||||||
### Phase 2: Planning (Required)
|
### Phase 2: Planning (Required)
|
||||||
|
|
||||||
**For BMad Method and Enterprise tracks:**
|
**For BMad Method and Enterprise tracks:**
|
||||||
1. Load the **PM agent** in a new chat
|
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`
|
3. Output: `PRD.md`
|
||||||
|
|
||||||
**For Quick Flow track:**
|
**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**
|
**Create Architecture**
|
||||||
1. Load the **Architect agent** in a new chat
|
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
|
3. Output: Architecture document with technical decisions
|
||||||
|
|
||||||
**Create Epics and Stories**
|
**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
|
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
|
3. The workflow uses both PRD and Architecture to create technically-informed stories
|
||||||
|
|
||||||
**Implementation Readiness Check** *(Highly Recommended)*
|
**Implementation Readiness Check** *(Highly Recommended)*
|
||||||
1. Load the **Architect agent** in a new chat
|
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
|
3. Validates cohesion across all planning documents
|
||||||
|
|
||||||
## Step 2: Build Your Project
|
## Step 2: Build Your Project
|
||||||
|
|
@ -124,7 +124,7 @@ Once planning is complete, move to implementation. **Each workflow should run in
|
||||||
|
|
||||||
### Initialize Sprint Planning
|
### 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
|
### The Build Cycle
|
||||||
|
|
||||||
|
|
@ -132,11 +132,11 @@ For each story, repeat this cycle with fresh chats:
|
||||||
|
|
||||||
| Step | Agent | Workflow | Purpose |
|
| Step | Agent | Workflow | Purpose |
|
||||||
| ---- | ----- | -------------- | ---------------------------------- |
|
| ---- | ----- | -------------- | ---------------------------------- |
|
||||||
| 1 | SM | `create-story` | Create story file from epic |
|
| 1 | SM | `create-story` (`bmad-bmm-create-story`) | Create story file from epic |
|
||||||
| 2 | DEV | `dev-story` | Implement the story |
|
| 2 | DEV | `dev-story` (`bmad-bmm-dev-story`) | Implement the story |
|
||||||
| 3 | DEV | `code-review` | Quality validation *(recommended)* |
|
| 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
|
## What You've Accomplished
|
||||||
|
|
||||||
|
|
@ -162,17 +162,17 @@ your-project/
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
| Workflow | Agent | Purpose |
|
| Workflow | Slash Command | Agent | Purpose |
|
||||||
| -------------------------------- | --------- | ------------------------------------ |
|
| -------------------------------- | ------------------------------------- | --------- | ------------------------------------ |
|
||||||
| `help` | Any | Get guidance on what to do next |
|
| `help` | `bmad-help` | Any | Get guidance on what to do next |
|
||||||
| `prd` | PM | Create Product Requirements Document |
|
| `create-prd` | `bmad-bmm-create-prd` | PM | Create Product Requirements Document |
|
||||||
| `create-architecture` | Architect | Create architecture document |
|
| `create-architecture` | `bmad-bmm-create-architecture` | Architect | Create architecture document |
|
||||||
| `create-epics-and-stories` | PM | Break down PRD into epics |
|
| `create-epics-and-stories` | `bmad-bmm-create-epics-and-stories` | PM | Break down PRD into epics |
|
||||||
| `check-implementation-readiness` | Architect | Validate planning cohesion |
|
| `check-implementation-readiness` | `bmad-bmm-check-implementation-readiness` | Architect | Validate planning cohesion |
|
||||||
| `sprint-planning` | SM | Initialize sprint tracking |
|
| `sprint-planning` | `bmad-bmm-sprint-planning` | SM | Initialize sprint tracking |
|
||||||
| `create-story` | SM | Create a story file |
|
| `create-story` | `bmad-bmm-create-story` | SM | Create a story file |
|
||||||
| `dev-story` | DEV | Implement a story |
|
| `dev-story` | `bmad-bmm-dev-story` | DEV | Implement a story |
|
||||||
| `code-review` | DEV | Review implemented code |
|
| `code-review` | `bmad-bmm-code-review` | DEV | Review implemented code |
|
||||||
|
|
||||||
## Common Questions
|
## 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.
|
Yes. The SM agent has a `correct-course` workflow for handling scope changes.
|
||||||
|
|
||||||
**What if I want to brainstorm first?**
|
**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?**
|
**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.
|
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
|
- **During workflows** — Agents guide you with questions and explanations
|
||||||
- **Community** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues)
|
- **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
|
## Key Takeaways
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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">
|
<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>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>Set {{epic_num}}, {{story_num}}, {{story_key}} from user input</action>
|
||||||
<action>GOTO step 2a</action>
|
<action>GOTO step 2</action>
|
||||||
</check>
|
</check>
|
||||||
|
|
||||||
<action>Check if {{sprint_status}} file exists for auto discover</action>
|
<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">
|
<check if="user provides epic-story number">
|
||||||
<action>Parse user input: extract epic_num, story_num, story_title</action>
|
<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>Set {{epic_num}}, {{story_num}}, {{story_key}} from user input</action>
|
||||||
<action>GOTO step 2a</action>
|
<action>GOTO step 2</action>
|
||||||
</check>
|
</check>
|
||||||
|
|
||||||
<check if="user provides story docs path">
|
<check if="user provides story docs path">
|
||||||
<action>Use user-provided path for story documents</action>
|
<action>Use user-provided path for story documents</action>
|
||||||
<action>GOTO step 2a</action>
|
<action>GOTO step 2</action>
|
||||||
</check>
|
</check>
|
||||||
</check>
|
</check>
|
||||||
|
|
||||||
|
|
@ -152,7 +152,7 @@ input_file_patterns:
|
||||||
<output>📊 Epic {{epic_num}} status updated to in-progress</output>
|
<output>📊 Epic {{epic_num}} status updated to in-progress</output>
|
||||||
</check>
|
</check>
|
||||||
|
|
||||||
<action>GOTO step 2a</action>
|
<action>GOTO step 2</action>
|
||||||
</check>
|
</check>
|
||||||
</step>
|
</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 -
|
(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 -->
|
Business context and value - Success criteria <!-- Previous story analysis for context continuity -->
|
||||||
<check if="story_num > 1">
|
<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:** -
|
<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
|
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
|
patterns - Testing approaches that worked/didn't work - Problems encountered and solutions found - Code patterns established <action>Extract
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@
|
||||||
- Set suggestion = ""
|
- Set suggestion = ""
|
||||||
- Set next_workflow = ""
|
- Set next_workflow = ""
|
||||||
- Set next_agent = ""
|
- 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>
|
||||||
|
|
||||||
<action>Attempt to load workflow status directly from `{output_folder}/bmm-workflow-status.yaml`:
|
<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
|
- Extract field_type, warning, suggestion, next_workflow, next_agent if present
|
||||||
- If file is missing, unreadable, or malformed:
|
- If file is missing, unreadable, or malformed:
|
||||||
- Keep defaults and continue in standalone mode
|
- 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>
|
</action>
|
||||||
|
|
||||||
<check if="status_exists == false">
|
<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>
|
<output>Note: Documentation workflow can run standalone. Continuing without progress tracking.</output>
|
||||||
<action>Set standalone_mode = true</action>
|
<action>Set standalone_mode = true</action>
|
||||||
<action>Set status_file_found = false</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>
|
<output>Note: This may be auto-invoked by prd for brownfield documentation.</output>
|
||||||
<ask>Continue with documentation? (y/n)</ask>
|
<ask>Continue with documentation? (y/n)</ask>
|
||||||
<check if="n">
|
<check if="n">
|
||||||
<output>{{suggestion}}</output>
|
<check if="suggestion != ''">
|
||||||
|
<output>{{suggestion}}</output>
|
||||||
|
</check>
|
||||||
<action>Exit workflow</action>
|
<action>Exit workflow</action>
|
||||||
</check>
|
</check>
|
||||||
</check>
|
</check>
|
||||||
|
|
@ -78,14 +95,33 @@
|
||||||
|
|
||||||
<check if="project-scan-report.json exists">
|
<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>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>Extract cached project_type_id(s) from state file if present</action>
|
||||||
<action>Calculate age of state file (current time - last_updated)</action>
|
<action>Calculate age of state file (current time - last_updated)</action>
|
||||||
|
|
||||||
<check if="state file age >= 24 hours">
|
<check if="state file age >= 24 hours">
|
||||||
<action>Display: "Found old state file (>24 hours). Starting fresh scan."</action>
|
<action>Display: "Found old state file (>24 hours). Starting fresh scan."</action>
|
||||||
<action>Create archive directory: {output_folder}/.archive/</action>
|
<action>Attempt to create archive directory: {output_folder}/.archive/</action>
|
||||||
<action>Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</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 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>
|
<action>Continue to Step 3</action>
|
||||||
</check>
|
</check>
|
||||||
|
|
||||||
|
|
@ -112,15 +148,25 @@ Your choice [1/2/3]:
|
||||||
|
|
||||||
<check if="user selects 1">
|
<check if="user selects 1">
|
||||||
<action>Set resume_mode = true</action>
|
<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>Set subworkflow_success = false</action>
|
||||||
<action>Load findings summaries from state file</action>
|
<action>Load findings summaries from state file</action>
|
||||||
<action>Load cached project_type_id(s) from state file</action>
|
<action>Load cached project_type_id(s) from state file</action>
|
||||||
|
|
||||||
<critical>CONDITIONAL CSV LOADING FOR RESUME:</critical>
|
<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>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>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>
|
<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>
|
<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>
|
||||||
|
|
||||||
<check if="user selects 2">
|
<check if="user selects 2">
|
||||||
<action>Create archive directory: {output_folder}/.archive/</action>
|
<action>Attempt to create archive directory: {output_folder}/.archive/</action>
|
||||||
<action>Move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</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>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>
|
<action>Continue to Step 3</action>
|
||||||
</check>
|
</check>
|
||||||
|
|
||||||
|
|
@ -198,6 +256,7 @@ Your choice [1/2/3]:
|
||||||
|
|
||||||
<check if="user selects 1">
|
<check if="user selects 1">
|
||||||
<action>Set workflow_mode = "full_rescan"</action>
|
<action>Set workflow_mode = "full_rescan"</action>
|
||||||
|
<action>Set scan_level = "standard"</action>
|
||||||
<action>Display: "Starting full project rescan..."</action>
|
<action>Display: "Starting full project rescan..."</action>
|
||||||
<action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</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>
|
<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">
|
<check if="index.md does not exist">
|
||||||
<action>Set workflow_mode = "initial_scan"</action>
|
<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>Display: "No existing documentation found. Starting initial project scan..."</action>
|
||||||
<action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</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>
|
<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.
|
<output>**Status Updated:** Progress tracking updated.
|
||||||
|
|
||||||
**Next Steps:**
|
**Next Steps:**
|
||||||
- **Next required:** {{next_workflow}} ({{next_agent}} agent)
|
|
||||||
- Run `bmad-help` if you need recommended next workflows.</output>
|
- 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>
|
||||||
|
|
||||||
<check if="status_file_found == false OR status_update_success != true">
|
<check if="status_file_found == false OR status_update_success != true">
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ Execute a validation checklist against a target file and report findings clearly
|
||||||
- Path-like tokens in checklist items
|
- Path-like tokens in checklist items
|
||||||
- First matching path from glob patterns supplied by checklist/input
|
- First matching path from glob patterns supplied by checklist/input
|
||||||
- Normalize all candidate paths relative to repo root and resolve `.`/`..`.
|
- 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 multiple valid candidates remain, prefer explicit key fields over inferred tokens.
|
||||||
- If no valid candidate is found, prompt user with schema example:
|
- 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`
|
- `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:
|
- If checklist requires edits/auto-fixes, follow safe-edit protocol:
|
||||||
- Ask for confirmation before editing.
|
- Ask for confirmation before editing.
|
||||||
- Create backup snapshot of target file before changes.
|
- 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.
|
- Generate reversible diff preview and show it to user.
|
||||||
- Apply edits only after user approval.
|
- Apply edits only after user approval.
|
||||||
- Run syntax/validation checks against edited file.
|
- Run syntax/validation checks against edited file.
|
||||||
- If validation fails or user cancels, rollback from backup and report rollback status.
|
- 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**
|
6. **Finalize**
|
||||||
- Confirm completion and provide the final validation summary.
|
- 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.
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,12 @@ async function runTests() {
|
||||||
console.log(`========================================${colors.reset}\n`);
|
console.log(`========================================${colors.reset}\n`);
|
||||||
|
|
||||||
const projectRoot = path.join(__dirname, '..');
|
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)
|
// 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`);
|
console.log(`${colors.yellow}Test Suite 11: Gemini Template Extension Guard${colors.reset}\n`);
|
||||||
|
|
||||||
try {
|
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 projectDir = path.join(tmpRoot, 'project');
|
||||||
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
||||||
await fs.ensureDir(projectDir);
|
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`);
|
console.log(`${colors.yellow}Test Suite 12: Manifest Stale Entry Cleanup Guard${colors.reset}\n`);
|
||||||
|
|
||||||
try {
|
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);
|
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', 'core'), path.join(bmadDir, 'core'));
|
||||||
await fs.copy(path.join(projectRoot, 'src', 'bmm'), path.join(bmadDir, 'bmm'));
|
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`);
|
console.log(`${colors.yellow}Test Suite 13: Internal Task Exposure Guard${colors.reset}\n`);
|
||||||
|
|
||||||
try {
|
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 projectDir = path.join(tmpRoot, 'project');
|
||||||
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
||||||
const commandsDir = path.join(tmpRoot, 'commands');
|
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`);
|
console.log(`${colors.yellow}Test Suite 16: Task/Tool Standalone + CRLF Guard${colors.reset}\n`);
|
||||||
|
|
||||||
try {
|
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 coreTasksDir = path.join(tmpRoot, '_bmad', 'core', 'tasks');
|
||||||
const coreToolsDir = path.join(tmpRoot, '_bmad', 'core', 'tools');
|
const coreToolsDir = path.join(tmpRoot, '_bmad', 'core', 'tools');
|
||||||
await fs.ensureDir(coreTasksDir);
|
await fs.ensureDir(coreTasksDir);
|
||||||
|
|
@ -717,7 +723,7 @@ internal: true
|
||||||
console.log(`${colors.yellow}Test Suite 18: Codex Task Visibility Guard${colors.reset}\n`);
|
console.log(`${colors.yellow}Test Suite 18: Codex Task Visibility Guard${colors.reset}\n`);
|
||||||
|
|
||||||
try {
|
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 projectDir = path.join(tmpRoot, 'project');
|
||||||
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
||||||
await fs.ensureDir(projectDir);
|
await fs.ensureDir(projectDir);
|
||||||
|
|
@ -751,7 +757,7 @@ internal: true
|
||||||
console.log(`${colors.yellow}Test Suite 19: Empty Artifact Target Guard${colors.reset}\n`);
|
console.log(`${colors.yellow}Test Suite 19: Empty Artifact Target Guard${colors.reset}\n`);
|
||||||
|
|
||||||
try {
|
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 projectDir = path.join(tmpRoot, 'project');
|
||||||
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
|
||||||
await fs.ensureDir(projectDir);
|
await fs.ensureDir(projectDir);
|
||||||
|
|
@ -856,6 +862,10 @@ internal: true
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
|
for (const tmpRoot of tmpRoots) {
|
||||||
|
await fs.remove(tmpRoot).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Summary
|
// Summary
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ class WorkflowCommandGenerator {
|
||||||
if (workflowRelPath.includes('_bmad/')) {
|
if (workflowRelPath.includes('_bmad/')) {
|
||||||
const parts = workflowRelPath.split(/_bmad\//);
|
const parts = workflowRelPath.split(/_bmad\//);
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
workflowRelPath = parts.slice(1).join('/');
|
workflowRelPath = parts.at(-1);
|
||||||
}
|
}
|
||||||
} else if (workflowRelPath.includes('/src/')) {
|
} else if (workflowRelPath.includes('/src/') || workflowRelPath.startsWith('src/')) {
|
||||||
const match = workflowRelPath.match(/\/src\/([^/]+)\/(.+)/);
|
const match = workflowRelPath.match(/(?:^|\/)src\/([^/]+)\/(.+)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
workflowRelPath = `${match[1]}/${match[2]}`;
|
workflowRelPath = `${match[1]}/${match[2]}`;
|
||||||
}
|
}
|
||||||
|
|
@ -119,30 +119,9 @@ class WorkflowCommandGenerator {
|
||||||
* Generate command content for a workflow
|
* Generate command content for a workflow
|
||||||
*/
|
*/
|
||||||
async generateCommandContent(workflow, bmadDir) {
|
async generateCommandContent(workflow, bmadDir) {
|
||||||
// Determine template based on workflow file type
|
// Load the workflow command template
|
||||||
const templatePath = path.join(path.dirname(this.templatePath), 'workflow-commander.md');
|
const template = await fs.readFile(this.templatePath, 'utf8');
|
||||||
|
const workflowPath = this.mapSourcePathToInstalled(workflow.path);
|
||||||
// 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]}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace template variables
|
// Replace template variables
|
||||||
return template
|
return template
|
||||||
|
|
@ -212,14 +191,15 @@ class WorkflowCommandGenerator {
|
||||||
When running any workflow:
|
When running any workflow:
|
||||||
1. Resolve loader paths:
|
1. Resolve loader paths:
|
||||||
- Primary: {project-root}/${this.bmadFolderName}/core/tasks/workflow.md
|
- 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
|
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
|
3. If primary is missing/unreadable, log a warning with the primary path and error
|
||||||
4. If fallback is also missing/unreadable, log an error with both attempted paths and stop
|
4. Only if the dev fallback exists and is readable, try the fallback path; otherwise skip it
|
||||||
5. LOAD the resolved workflow loader file
|
5. If no readable loader is found, log an error with all attempted readable paths and stop
|
||||||
6. Pass the workflow path as 'workflow-config' parameter
|
6. LOAD the resolved workflow loader file
|
||||||
7. Follow workflow.md instructions EXACTLY
|
7. Pass the workflow path as 'workflow-config' parameter
|
||||||
8. Save outputs after EACH section
|
8. Follow workflow.md instructions EXACTLY
|
||||||
|
9. Save outputs after EACH section
|
||||||
|
|
||||||
## Modes
|
## Modes
|
||||||
- Normal: Full interaction
|
- Normal: Full interaction
|
||||||
|
|
@ -230,21 +210,33 @@ When running any workflow:
|
||||||
}
|
}
|
||||||
|
|
||||||
transformWorkflowPath(workflowPath) {
|
transformWorkflowPath(workflowPath) {
|
||||||
let transformed = workflowPath;
|
return this.mapSourcePathToInstalled(workflowPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (workflowPath.includes('/src/bmm/')) {
|
mapSourcePathToInstalled(sourcePath, includeProjectRootPrefix = false) {
|
||||||
const match = workflowPath.match(/\/src\/bmm\/(.+)/);
|
if (!sourcePath) {
|
||||||
if (match) {
|
return sourcePath;
|
||||||
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]}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
async loadWorkflowManifest(bmadDir) {
|
||||||
|
|
|
||||||
|
|
@ -813,7 +813,6 @@ class ModuleManager {
|
||||||
const newline = frontmatterMatch[0].includes('\r\n') ? '\r\n' : '\n';
|
const newline = frontmatterMatch[0].includes('\r\n') ? '\r\n' : '\n';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const yaml = require('yaml');
|
|
||||||
const parsed = yaml.parse(frontmatterMatch[1]);
|
const parsed = yaml.parse(frontmatterMatch[1]);
|
||||||
|
|
||||||
if (!parsed || typeof parsed !== 'object' || !Object.prototype.hasOwnProperty.call(parsed, 'web_bundle')) {
|
if (!parsed || typeof parsed !== 'object' || !Object.prototype.hasOwnProperty.call(parsed, 'web_bundle')) {
|
||||||
|
|
@ -897,7 +896,6 @@ class ModuleManager {
|
||||||
let manifestData = {};
|
let manifestData = {};
|
||||||
if (await fs.pathExists(manifestPath)) {
|
if (await fs.pathExists(manifestPath)) {
|
||||||
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
||||||
const yaml = require('yaml');
|
|
||||||
manifestData = yaml.parse(manifestContent);
|
manifestData = yaml.parse(manifestContent);
|
||||||
}
|
}
|
||||||
if (!manifestData.agentCustomizations) {
|
if (!manifestData.agentCustomizations) {
|
||||||
|
|
@ -906,7 +904,6 @@ class ModuleManager {
|
||||||
manifestData.agentCustomizations[path.relative(bmadDir, customizePath)] = originalHash;
|
manifestData.agentCustomizations[path.relative(bmadDir, customizePath)] = originalHash;
|
||||||
|
|
||||||
// Write back to manifest
|
// Write back to manifest
|
||||||
const yaml = require('yaml');
|
|
||||||
// Clean the manifest data to remove any non-serializable values
|
// Clean the manifest data to remove any non-serializable values
|
||||||
const cleanManifestData = structuredClone(manifestData);
|
const cleanManifestData = structuredClone(manifestData);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue