refactor: centralize monorepo context detection logic by removing duplicated checks from numerous workflow files and updating related tests.
This commit is contained in:
parent
a5bda6a80e
commit
d05b9f87d5
|
|
@ -51,11 +51,6 @@ This uses **step-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`, `user_skill_level`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
||||||
### 2. First Step EXECUTION
|
### 2. First Step EXECUTION
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ main_config: '{project-root}/_bmad/bmm/config.yaml'
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ main_config: '{project-root}/_bmad/bmm/config.yaml'
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ main_config: '{project-root}/_bmad/bmm/config.yaml'
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -46,15 +46,6 @@ This uses **step-file architecture** for disciplined execution:
|
||||||
|
|
||||||
## INITIALIZATION SEQUENCE
|
## INITIALIZATION SEQUENCE
|
||||||
|
|
||||||
### 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
- `date` as system-generated current datetime
|
- `date` as system-generated current datetime
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,6 @@ This uses **step-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
- `date` as system-generated current datetime
|
- `date` as system-generated current datetime
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,6 @@ This uses **step-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,6 @@ This uses **micro-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,6 @@ description: 'Critical validation workflow that assesses PRD, Architecture, and
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,6 @@ This uses **micro-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,6 @@ This uses **step-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`
|
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`
|
||||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,7 @@
|
||||||
- [x] Done - Item completed successfully
|
- [x] Done - Item completed successfully
|
||||||
- [N/A] Skip - Item not applicable to this change
|
- [N/A] Skip - Item not applicable to this change
|
||||||
- [!] Action-needed - Item requires attention or follow-up
|
- [!] Action-needed - Item requires attention or follow-up
|
||||||
### 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
<action>Maintain running notes of findings and impacts discovered</action>
|
|
||||||
<action>Present checklist progress after each major section</action>
|
<action>Present checklist progress after each major section</action>
|
||||||
|
|
||||||
<action if="checklist cannot be completed">Identify blocking issues and work with user to resolve before continuing</action>
|
<action if="checklist cannot be completed">Identify blocking issues and work with user to resolve before continuing</action>
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,6 @@
|
||||||
<critical>🎯 ZERO USER INTERVENTION: Process should be fully automated except for initial epic/story selection or missing documents</critical>
|
<critical>🎯 ZERO USER INTERVENTION: Process should be fully automated except for initial epic/story selection or missing documents</critical>
|
||||||
|
|
||||||
<step n="1" goal="Determine target story">
|
<step n="1" goal="Determine target story">
|
||||||
<check if="{project-root}/_bmad/.current_project exists">
|
|
||||||
<action>Read content as project_suffix</action>
|
|
||||||
<!-- Sanitization and Validation -->
|
|
||||||
<action>Trim whitespace and newlines from project_suffix</action>
|
|
||||||
<check if="project_suffix contains '..' or starts with '/' or starts with '\'">
|
|
||||||
<output>🚫 Security Error: Invalid project context path detected.</output>
|
|
||||||
<action>HALT</action>
|
|
||||||
</check>
|
|
||||||
<check if="project_suffix matches regex '[^a-zA-Z0-9._-]|^\s*$'">
|
|
||||||
<output>🚫 Error: Project context must only contain alphanumeric characters, dots, dashes, or underscores.</output>
|
|
||||||
<action>HALT</action>
|
|
||||||
</check>
|
|
||||||
<action>Override output_folder to {project-root}/_bmad-output/{project_suffix}</action>
|
|
||||||
<action>Output "Monorepo context detected. Output folder redirected to: {output_folder}"</action>
|
|
||||||
</check>
|
|
||||||
|
|
||||||
<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>
|
||||||
|
|
|
||||||
|
|
@ -13,24 +13,6 @@
|
||||||
<critical>User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.</critical>
|
<critical>User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.</critical>
|
||||||
|
|
||||||
<step n="1" goal="Find next ready story and load it" tag="sprint-status">
|
<step n="1" goal="Find next ready story and load it" tag="sprint-status">
|
||||||
<check if="{project-root}/_bmad/.current_project exists">
|
|
||||||
<action>Read content as project_suffix</action>
|
|
||||||
<!-- Sanitization and Validation -->
|
|
||||||
<action>Trim whitespace and newlines from project_suffix</action>
|
|
||||||
<check if="project_suffix contains '..' or starts with '/' or starts with '\'">
|
|
||||||
<output>🚫 Security Error: Invalid project context path detected.</output>
|
|
||||||
<action>HALT</action>
|
|
||||||
</check>
|
|
||||||
<check if="project_suffix matches regex '[^a-zA-Z0-9._-]|^\s*$'">
|
|
||||||
<output>🚫 Error: Project context must only contain alphanumeric characters, dots, dashes, or underscores.</output>
|
|
||||||
<action>HALT</action>
|
|
||||||
</check>
|
|
||||||
<check if="project_suffix.length > 100">
|
|
||||||
<output>🚫 Error: Project context name is too long (max 100 characters).</output>
|
|
||||||
<action>HALT</action>
|
|
||||||
</check>
|
|
||||||
<action>Override output_folder to {project-root}/_bmad-output/{project_suffix}</action>
|
|
||||||
</check>
|
|
||||||
|
|
||||||
<check if="{{story_path}} is provided">
|
<check if="{{story_path}} is provided">
|
||||||
<action>Use {{story_path}} directly</action>
|
<action>Use {{story_path}} directly</action>
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,6 @@
|
||||||
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
|
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
|
||||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||||
|
|
||||||
## 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
3. Re-derive dependent path variables to reflect the new `output_folder`:
|
|
||||||
- `implementation_artifacts`: `{output_folder}/implementation`
|
|
||||||
- `planning_artifacts`: `{output_folder}/planning`
|
|
||||||
|
|
||||||
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
||||||
<critical>Generate all documents in {document_output_language}</critical>
|
<critical>Generate all documents in {document_output_language}</critical>
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,6 @@
|
||||||
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml</critical>
|
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml</critical>
|
||||||
|
|
||||||
## 📚 Document Discovery
|
## 📚 Document Discovery
|
||||||
### 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- Full Epic Loading
|
- Full Epic Loading
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,6 @@
|
||||||
|
|
||||||
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
|
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
|
||||||
|
|
||||||
## 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-status/workflow.yaml</critical>
|
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-status/workflow.yaml</critical>
|
||||||
<critical>Modes: interactive (default), validate, data</critical>
|
<critical>Modes: interactive (default), validate, data</critical>
|
||||||
<critical>⚠️ ABSOLUTELY NO TIME ESTIMATES. Do NOT mention hours, days, weeks, or timelines.</critical>
|
<critical>⚠️ ABSOLUTELY NO TIME ESTIMATES. Do NOT mention hours, days, weeks, or timelines.</critical>
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,6 @@ This uses **step-file architecture** for focused execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
||||||
|
|
||||||
- `user_name`, `communication_language`, `user_skill_level`
|
- `user_name`, `communication_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,6 @@ This uses **step-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
||||||
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
|
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,6 @@
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
<step n="3" goal="Check for existing documentation and determine workflow mode" if="resume_mode == false">
|
<step n="3" goal="Check for existing documentation and determine workflow mode" if="resume_mode == false">
|
||||||
<action>Check if {project_knowledge}/index.md exists</action>
|
<action>Check if {project_knowledge}/index.md exists</action>
|
||||||
|
|
|
||||||
|
|
@ -95,15 +95,7 @@ Your choice [1/2/3]:
|
||||||
- Best for: Quick project overview, initial understanding
|
- Best for: Quick project overview, initial understanding
|
||||||
- File reading: Minimal (configs, README, package.json, etc.)
|
- File reading: Minimal (configs, README, package.json, etc.)
|
||||||
|
|
||||||
## 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
json, etc.)
|
|
||||||
|
|
||||||
**2. Deep Scan** (10-30 minutes)
|
**2. Deep Scan** (10-30 minutes)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,6 @@ This uses **micro-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `user_name`
|
- `project_name`, `output_folder`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,6 @@ Check project for existing test framework:
|
||||||
- Search online for current recommended test framework for that stack
|
- Search online for current recommended test framework for that stack
|
||||||
- Suggest the meta framework and use it (or ask user to confirm)
|
- Suggest the meta framework and use it (or ask user to confirm)
|
||||||
|
|
||||||
### 1. Configuration Loading
|
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
### Step 1: Identify Features
|
### Step 1: Identify Features
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,6 @@ This uses **micro-file architecture** for disciplined execution:
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
Load config from `{project-root}/_bmad/core/config.yaml` and resolve:
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `user_name`
|
- `project_name`, `output_folder`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,6 @@ This uses **micro-file architecture** with **sequential conversation orchestrati
|
||||||
|
|
||||||
Load and read full config from {main_config} and resolve basic variables.
|
Load and read full config from {main_config} and resolve basic variables.
|
||||||
|
|
||||||
**Monorepo Context Check:**
|
|
||||||
1. Check if `{project-root}/_bmad/.current_project` exists.
|
|
||||||
2. If it exists, read its content as `{project_suffix}` and override output folder:
|
|
||||||
- `output_folder`: `{project-root}/_bmad-output/{project_suffix}`
|
|
||||||
|
|
||||||
- `project_name`, `output_folder`, `user_name`
|
- `project_name`, `output_folder`, `user_name`
|
||||||
- `communication_language`, `document_output_language`, `user_skill_level`
|
- `communication_language`, `document_output_language`, `user_skill_level`
|
||||||
- `date` as a system-generated value
|
- `date` as a system-generated value
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
/**
|
||||||
|
* Context Logic Integration Tests
|
||||||
|
*
|
||||||
|
* Validates the centralized monorepo context logic deduplication:
|
||||||
|
* 1. context-logic.js exports a valid XML block
|
||||||
|
* 2. All workflow templates that need it use the {{monorepo_context_logic}} placeholder
|
||||||
|
* 3. No stale hardcoded <monorepo-context-check> blocks exist in templates
|
||||||
|
* 4. src/core/tasks/workflow.xml uses the placeholder (not a hardcoded block)
|
||||||
|
* 5. All JS consumers correctly import context-logic.js
|
||||||
|
* 6. MONOREPO_CONTEXT_LOGIC string integrity (key fields are present)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
// ANSI colors
|
||||||
|
const c = {
|
||||||
|
reset: '\u001B[0m',
|
||||||
|
green: '\u001B[32m',
|
||||||
|
red: '\u001B[31m',
|
||||||
|
yellow: '\u001B[33m',
|
||||||
|
cyan: '\u001B[36m',
|
||||||
|
dim: '\u001B[2m',
|
||||||
|
};
|
||||||
|
|
||||||
|
let passed = 0;
|
||||||
|
let failed = 0;
|
||||||
|
|
||||||
|
function ok(condition, testName, detail = '') {
|
||||||
|
if (condition) {
|
||||||
|
console.log(`${c.green}✓${c.reset} ${testName}`);
|
||||||
|
passed++;
|
||||||
|
} else {
|
||||||
|
console.log(`${c.red}✗${c.reset} ${testName}`);
|
||||||
|
if (detail) console.log(` ${c.dim}${detail}${c.reset}`);
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readFile(p) {
|
||||||
|
return fs.readFile(p, 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exists(p) {
|
||||||
|
return fs.pathExists(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runTests() {
|
||||||
|
console.log(`${c.cyan}============================================================`);
|
||||||
|
console.log(' Context Logic Integration Tests');
|
||||||
|
console.log(`============================================================${c.reset}\n`);
|
||||||
|
|
||||||
|
const root = path.join(__dirname, '..');
|
||||||
|
const sharedDir = path.join(root, 'tools/cli/installers/lib/ide/shared');
|
||||||
|
const templatesDir = path.join(root, 'tools/cli/installers/lib/ide/templates');
|
||||||
|
const combinedDir = path.join(templatesDir, 'combined');
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
// Suite 1: context-logic.js module integrity
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
console.log(`${c.yellow}Suite 1: context-logic.js module integrity${c.reset}\n`);
|
||||||
|
|
||||||
|
const contextLogicPath = path.join(sharedDir, 'context-logic.js');
|
||||||
|
ok(await exists(contextLogicPath), 'context-logic.js file exists');
|
||||||
|
|
||||||
|
let MONOREPO_CONTEXT_LOGIC;
|
||||||
|
try {
|
||||||
|
const mod = require(contextLogicPath);
|
||||||
|
ok(typeof mod.MONOREPO_CONTEXT_LOGIC === 'string', 'exports MONOREPO_CONTEXT_LOGIC as a string');
|
||||||
|
ok(mod.MONOREPO_CONTEXT_LOGIC.length > 0, 'MONOREPO_CONTEXT_LOGIC is non-empty');
|
||||||
|
MONOREPO_CONTEXT_LOGIC = mod.MONOREPO_CONTEXT_LOGIC;
|
||||||
|
} catch (error) {
|
||||||
|
ok(false, 'context-logic.js is require()-able', error.message);
|
||||||
|
MONOREPO_CONTEXT_LOGIC = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key content checks
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('<monorepo-context-check'), 'has opening <monorepo-context-check> tag');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('</monorepo-context-check>'), 'has closing </monorepo-context-check> tag');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('#project:NAME'), 'documents #project:NAME syntax');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('#p:NAME'), 'documents #p:NAME short alias');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('.current_project'), 'includes .current_project fallback logic');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('path traversal'), 'includes path traversal security check');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('output_folder'), 'overrides output_folder path variable');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('planning_artifacts'), 'overrides planning_artifacts path variable');
|
||||||
|
ok(MONOREPO_CONTEXT_LOGIC.includes('HALT'), 'halts on security violation');
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
// Suite 2: JS consumers import context-logic.js correctly
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
console.log(`${c.yellow}Suite 2: JS consumers import context-logic.js${c.reset}\n`);
|
||||||
|
|
||||||
|
const consumers = [
|
||||||
|
{
|
||||||
|
file: 'tools/cli/installers/lib/core/installer.js',
|
||||||
|
expectedImport: "require('../ide/shared/context-logic')",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: 'tools/cli/installers/lib/ide/_config-driven.js',
|
||||||
|
expectedImport: "require('./shared/context-logic')",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: 'tools/cli/installers/lib/ide/shared/workflow-command-generator.js',
|
||||||
|
expectedImport: "require('./context-logic')",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { file, expectedImport } of consumers) {
|
||||||
|
const fullPath = path.join(root, file);
|
||||||
|
const content = await readFile(fullPath);
|
||||||
|
ok(content.includes(expectedImport), `${path.basename(file)} imports context-logic correctly`);
|
||||||
|
ok(content.includes("replaceAll('{{monorepo_context_logic}}'"), `${path.basename(file)} uses replaceAll for placeholder`);
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
// Suite 3: Templates use placeholder, not hardcoded blocks
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
console.log(`${c.yellow}Suite 3: Templates use {{monorepo_context_logic}} placeholder${c.reset}\n`);
|
||||||
|
|
||||||
|
// These templates MUST have the placeholder (they are rendered directly as IDE workflow commands)
|
||||||
|
const mustHavePlaceholder = [
|
||||||
|
path.join(templatesDir, 'workflow-command-template.md'),
|
||||||
|
path.join(templatesDir, 'workflow-commander.md'),
|
||||||
|
path.join(combinedDir, 'antigravity.md'),
|
||||||
|
path.join(combinedDir, 'claude-workflow.md'),
|
||||||
|
path.join(combinedDir, 'claude-workflow-yaml.md'),
|
||||||
|
path.join(combinedDir, 'default-workflow.md'),
|
||||||
|
path.join(combinedDir, 'default-workflow-yaml.md'),
|
||||||
|
path.join(combinedDir, 'kiro-workflow.md'),
|
||||||
|
path.join(combinedDir, 'opencode-workflow.md'),
|
||||||
|
path.join(combinedDir, 'windsurf-workflow.md'),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const filePath of mustHavePlaceholder) {
|
||||||
|
const rel = path.relative(root, filePath);
|
||||||
|
const content = await readFile(filePath);
|
||||||
|
ok(content.includes('{{monorepo_context_logic}}'), `${path.basename(filePath)} has {{monorepo_context_logic}} placeholder`);
|
||||||
|
// Must NOT have raw hardcoded block (only the shared module should have it)
|
||||||
|
ok(!content.includes('<monorepo-context-check'), `${path.basename(filePath)} has NO hardcoded <monorepo-context-check> block`);
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
// Suite 4: No rogue hardcoded blocks anywhere in templates dir
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
console.log(`${c.yellow}Suite 4: No hardcoded blocks in templates directory${c.reset}\n`);
|
||||||
|
|
||||||
|
const walkDir = async (dir) => {
|
||||||
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||||
|
const files = [];
|
||||||
|
for (const e of entries) {
|
||||||
|
const full = path.join(dir, e.name);
|
||||||
|
if (e.isDirectory()) files.push(...(await walkDir(full)));
|
||||||
|
else if (e.isFile()) files.push(full);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
};
|
||||||
|
|
||||||
|
const allTemplateFiles = await walkDir(templatesDir);
|
||||||
|
const rogueFiles = [];
|
||||||
|
for (const f of allTemplateFiles) {
|
||||||
|
const content = await readFile(f);
|
||||||
|
if (content.includes('<monorepo-context-check') && !f.includes('context-logic.js')) {
|
||||||
|
rogueFiles.push(path.relative(root, f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok(
|
||||||
|
rogueFiles.length === 0,
|
||||||
|
`No hardcoded <monorepo-context-check> blocks in templates (found ${rogueFiles.length})`,
|
||||||
|
rogueFiles.length > 0 ? `Rogue files: ${rogueFiles.join(', ')}` : '',
|
||||||
|
);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
// Suite 5: src/core/tasks/workflow.xml uses placeholder
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
console.log(`${c.yellow}Suite 5: src/core/tasks/workflow.xml uses placeholder${c.reset}\n`);
|
||||||
|
|
||||||
|
const srcWorkflowXml = path.join(root, 'src/core/tasks/workflow.xml');
|
||||||
|
ok(await exists(srcWorkflowXml), 'src/core/tasks/workflow.xml exists');
|
||||||
|
const srcXmlContent = await readFile(srcWorkflowXml);
|
||||||
|
ok(srcXmlContent.includes('{{monorepo_context_logic}}'), 'workflow.xml (src) uses {{monorepo_context_logic}} placeholder');
|
||||||
|
ok(!srcXmlContent.includes('<monorepo-context-check'), 'workflow.xml (src) has NO hardcoded <monorepo-context-check> block');
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
// Results
|
||||||
|
// ────────────────────────────────────────────────────────────
|
||||||
|
console.log(`\n${c.cyan}============================================================`);
|
||||||
|
console.log(` Results: ${c.green}${passed} passed${c.reset}${c.cyan}, ${c.red}${failed} failed${c.reset}${c.cyan}`);
|
||||||
|
console.log(`============================================================${c.reset}\n`);
|
||||||
|
|
||||||
|
if (failed === 0) {
|
||||||
|
console.log(`${c.green}✨ All context-logic integration tests passed!${c.reset}\n`);
|
||||||
|
process.exit(0);
|
||||||
|
} else {
|
||||||
|
console.log(`${c.red}❌ ${failed} test(s) failed${c.reset}\n`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runTests().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
@ -1,9 +1,19 @@
|
||||||
/**
|
/**
|
||||||
* Monorepo Support Validation Tests
|
* Monorepo Support Validation Tests
|
||||||
*
|
*
|
||||||
* Verifies that:
|
* Architecture after deduplication:
|
||||||
|
* - Monorepo context logic lives ONLY in context-logic.js
|
||||||
|
* - workflow.xml (src) uses {{monorepo_context_logic}} placeholder → injected at install time
|
||||||
|
* - Individual source workflow files do NOT have inline checks (that's the deduplication!)
|
||||||
|
* - Only code-review/instructions.xml, dev-story/instructions.xml, create-story/instructions.xml
|
||||||
|
* and advanced-elicitation/workflow.xml are XML workflows checked; XML workflows that go through
|
||||||
|
* workflow.xml no longer need inline checks.
|
||||||
|
*
|
||||||
|
* Verifies:
|
||||||
* 1. The set-project workflow is correctly registered.
|
* 1. The set-project workflow is correctly registered.
|
||||||
* 2. All core and BMM workflows contain the monorepo context logic.
|
* 2. No source workflow file has a stale inline "Monorepo Context Check" block.
|
||||||
|
* 3. Only the canonical SINGLE source (context-logic.js) defines the check.
|
||||||
|
* 4. set-project implementation still manages .current_project.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
@ -55,46 +65,39 @@ async function runTests() {
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// 2. Verify context logic in workflows
|
// 2. Verify NO stale inline "Monorepo Context Check" blocks in source workflow files
|
||||||
console.log(`${colors.yellow}Test Suite 2: Workflow Context Logic${colors.reset}\n`);
|
// These are redundant since workflow.xml now handles context injection via context-logic.js
|
||||||
|
console.log(`${colors.yellow}Test Suite 2: No Stale Inline Monorepo Context Checks${colors.reset}\n`);
|
||||||
|
console.log(` ${colors.dim}(Inline checks were moved to workflow.xml via context-logic.js)${colors.reset}\n`);
|
||||||
|
|
||||||
const workflowFiles = glob.sync('src/{core,bmm}/workflows/**/*.{md,xml}', { cwd: projectRoot });
|
const workflowFiles = glob.sync('src/{core,bmm}/workflows/**/*.{md,xml}', { cwd: projectRoot });
|
||||||
|
|
||||||
// Workflows that MUST have the check
|
|
||||||
const requiredWorkflows = [
|
|
||||||
'brainstorming',
|
|
||||||
'party-mode',
|
|
||||||
'create-product-brief',
|
|
||||||
'create-prd',
|
|
||||||
'create-architecture',
|
|
||||||
'code-review',
|
|
||||||
'create-story',
|
|
||||||
'dev-story',
|
|
||||||
'set-project', // Should not have the check itself, but let's exclude it
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const file of workflowFiles) {
|
for (const file of workflowFiles) {
|
||||||
const basename = path.basename(path.dirname(file));
|
// skip the context-logic source itself (it's the canonical source)
|
||||||
if (basename === 'set-project' || basename === '0-context') continue;
|
if (file.includes('context-logic')) continue;
|
||||||
|
|
||||||
const content = await fs.readFile(path.join(projectRoot, file), 'utf8');
|
const content = await fs.readFile(path.join(projectRoot, file), 'utf8');
|
||||||
const isXml = file.endsWith('.xml');
|
|
||||||
|
|
||||||
if (isXml) {
|
assert(!content.includes('**Monorepo Context Check:**'), `No stale inline check block in: ${file}`);
|
||||||
assert(content.includes('_bmad/.current_project'), `XML workflow contains context check: ${file}`);
|
|
||||||
} else {
|
|
||||||
// Only check Markdown files that look like main workflow/instruction files
|
|
||||||
const filename = path.basename(file);
|
|
||||||
if (filename.includes('workflow') || filename.includes('instructions')) {
|
|
||||||
assert(content.includes('_bmad/.current_project'), `Markdown workflow contains context check: ${file}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// 3. Verify set-project implementation
|
// 3. Verify canonical source is context-logic.js (single source of truth)
|
||||||
console.log(`${colors.yellow}Test Suite 3: set-project Implementation${colors.reset}\n`);
|
console.log(`${colors.yellow}Test Suite 3: Single Source of Truth${colors.reset}\n`);
|
||||||
|
|
||||||
|
const contextLogicPath = path.join(projectRoot, 'tools/cli/installers/lib/ide/shared/context-logic.js');
|
||||||
|
assert(await fs.pathExists(contextLogicPath), 'context-logic.js exists as canonical source');
|
||||||
|
|
||||||
|
const srcWorkflowXml = path.join(projectRoot, 'src/core/tasks/workflow.xml');
|
||||||
|
const xmlContent = await fs.readFile(srcWorkflowXml, 'utf8');
|
||||||
|
assert(xmlContent.includes('{{monorepo_context_logic}}'), 'workflow.xml uses {{monorepo_context_logic}} placeholder');
|
||||||
|
assert(!xmlContent.includes('**Monorepo Context Check:**'), 'workflow.xml has no stale inline check');
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// 4. Verify set-project implementation
|
||||||
|
console.log(`${colors.yellow}Test Suite 4: set-project Implementation${colors.reset}\n`);
|
||||||
try {
|
try {
|
||||||
const setProjectPath = path.join(projectRoot, 'src/bmm/workflows/0-context/set-project/workflow.md');
|
const setProjectPath = path.join(projectRoot, 'src/bmm/workflows/0-context/set-project/workflow.md');
|
||||||
const exists = await fs.pathExists(setProjectPath);
|
const exists = await fs.pathExists(setProjectPath);
|
||||||
|
|
@ -102,6 +105,7 @@ async function runTests() {
|
||||||
if (exists) {
|
if (exists) {
|
||||||
const content = await fs.readFile(setProjectPath, 'utf8');
|
const content = await fs.readFile(setProjectPath, 'utf8');
|
||||||
assert(content.includes('_bmad/.current_project'), 'set-project implementation manages .current_project');
|
assert(content.includes('_bmad/.current_project'), 'set-project implementation manages .current_project');
|
||||||
|
assert(content.includes('my-app'), 'set-project examples use generic public-friendly names');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert(false, 'set-project check failed', error.message);
|
assert(false, 'set-project check failed', error.message);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue