Compare commits
5 Commits
decbd2f9bd
...
a0b762bee5
| Author | SHA1 | Date |
|---|---|---|
|
|
a0b762bee5 | |
|
|
5b5cb1a396 | |
|
|
98c1fa8282 | |
|
|
ae7b3a7930 | |
|
|
3103c3d4ce |
|
|
@ -78,7 +78,6 @@ your-project/
|
||||||
├── _bmad/ # BMad configuration
|
├── _bmad/ # BMad configuration
|
||||||
├── _bmad-output/
|
├── _bmad-output/
|
||||||
│ ├── PRD.md # Your requirements document
|
│ ├── PRD.md # Your requirements document
|
||||||
│ └── bmm-workflow-status.yaml # Progress tracking
|
|
||||||
└── ...
|
└── ...
|
||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
@ -143,7 +142,7 @@ your-project/
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
| Type | Example |
|
| Type | Example |
|
||||||
| ----------------- | ---------------------------- |
|
| ----------------- | ----------------------------- |
|
||||||
| **Index/Landing** | `core-concepts/index.md` |
|
| **Index/Landing** | `core-concepts/index.md` |
|
||||||
| **Concept** | `what-are-agents.md` |
|
| **Concept** | `what-are-agents.md` |
|
||||||
| **Feature** | `quick-flow.md` |
|
| **Feature** | `quick-flow.md` |
|
||||||
|
|
|
||||||
|
|
@ -8,55 +8,7 @@
|
||||||
|
|
||||||
<critical>This router determines workflow mode and delegates to specialized sub-workflows</critical>
|
<critical>This router determines workflow mode and delegates to specialized sub-workflows</critical>
|
||||||
|
|
||||||
<step n="1" goal="Validate workflow and get project info">
|
<step n="1" goal="Check for ability to resume and determine workflow mode">
|
||||||
|
|
||||||
<invoke-workflow path="{project-root}/_bmad/bmm/workflows/workflow-status">
|
|
||||||
<param>mode: data</param>
|
|
||||||
<param>data_request: project_config</param>
|
|
||||||
</invoke-workflow>
|
|
||||||
|
|
||||||
<check if="status_exists == false">
|
|
||||||
<output>{{suggestion}}</output>
|
|
||||||
<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>
|
|
||||||
</check>
|
|
||||||
|
|
||||||
<check if="status_exists == true">
|
|
||||||
<action>Store {{status_file_path}} for later updates</action>
|
|
||||||
<action>Set status_file_found = true</action>
|
|
||||||
|
|
||||||
<!-- Extract brownfield/greenfield from status data -->
|
|
||||||
<check if="field_type == 'greenfield'">
|
|
||||||
<output>Note: This is a greenfield project. Documentation workflow is typically for brownfield projects.</output>
|
|
||||||
<ask>Continue anyway to document planning artifacts? (y/n)</ask>
|
|
||||||
<check if="n">
|
|
||||||
<action>Exit workflow</action>
|
|
||||||
</check>
|
|
||||||
</check>
|
|
||||||
|
|
||||||
<!-- Now validate sequencing -->
|
|
||||||
<invoke-workflow path="{project-root}/_bmad/bmm/workflows/workflow-status">
|
|
||||||
<param>mode: validate</param>
|
|
||||||
<param>calling_workflow: document-project</param>
|
|
||||||
</invoke-workflow>
|
|
||||||
|
|
||||||
<check if="warning != ''">
|
|
||||||
<output>{{warning}}</output>
|
|
||||||
<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>
|
|
||||||
<action>Exit workflow</action>
|
|
||||||
</check>
|
|
||||||
</check>
|
|
||||||
</check>
|
|
||||||
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step n="2" goal="Check for resumability and determine workflow mode">
|
|
||||||
<critical>SMART LOADING STRATEGY: Check state file FIRST before loading any CSV files</critical>
|
|
||||||
|
|
||||||
<action>Check for existing state file at: {project_knowledge}/project-scan-report.json</action>
|
<action>Check for existing state file at: {project_knowledge}/project-scan-report.json</action>
|
||||||
|
|
||||||
<check if="project-scan-report.json exists">
|
<check if="project-scan-report.json exists">
|
||||||
|
|
@ -175,47 +127,4 @@ Your choice [1/2/3]:
|
||||||
|
|
||||||
</step>
|
</step>
|
||||||
|
|
||||||
<step n="4" goal="Update status and complete">
|
|
||||||
|
|
||||||
<check if="status_file_found == true">
|
|
||||||
<invoke-workflow path="{project-root}/_bmad/bmm/workflows/workflow-status">
|
|
||||||
<param>mode: update</param>
|
|
||||||
<param>action: complete_workflow</param>
|
|
||||||
<param>workflow_name: document-project</param>
|
|
||||||
</invoke-workflow>
|
|
||||||
|
|
||||||
<check if="success == true">
|
|
||||||
<output>Status updated!</output>
|
|
||||||
</check>
|
|
||||||
</check>
|
|
||||||
|
|
||||||
<output>**✅ Document Project Workflow Complete, {user_name}!**
|
|
||||||
|
|
||||||
**Documentation Generated:**
|
|
||||||
|
|
||||||
- Mode: {{workflow_mode}}
|
|
||||||
- Scan Level: {{scan_level}}
|
|
||||||
- Output: {project_knowledge}/index.md and related files
|
|
||||||
|
|
||||||
{{#if status_file_found}}
|
|
||||||
**Status Updated:**
|
|
||||||
|
|
||||||
- Progress tracking updated
|
|
||||||
|
|
||||||
**Next Steps:**
|
|
||||||
|
|
||||||
- **Next required:** {{next_workflow}} ({{next_agent}} agent)
|
|
||||||
|
|
||||||
Check status anytime with: `workflow-status`
|
|
||||||
{{else}}
|
|
||||||
**Next Steps:**
|
|
||||||
Since no workflow is in progress:
|
|
||||||
|
|
||||||
- Refer to the BMM workflow guide if unsure what to do next
|
|
||||||
- Or run `workflow-init` to create a workflow path and get guided next steps
|
|
||||||
{{/if}}
|
|
||||||
</output>
|
|
||||||
|
|
||||||
</step>
|
|
||||||
|
|
||||||
</workflow>
|
</workflow>
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,56 @@
|
||||||
For external official modules to be discoverable during install, ensure an entry for the external repo is added to external-official-modules.yaml.
|
For external official modules to be discoverable during install, ensure an entry for the external repo is added to external-official-modules.yaml.
|
||||||
|
|
||||||
For community modules - this will be handled in a different way. This file is only for registration of modules under the bmad-code-org.
|
For community modules - this will be handled in a different way. This file is only for registration of modules under the bmad-code-org.
|
||||||
|
|
||||||
|
## Post-Install Notes
|
||||||
|
|
||||||
|
Modules can display setup guidance to users after configuration is collected during `npx bmad-method install`. Notes are defined in the module's own `module.yaml` — no changes to the installer are needed.
|
||||||
|
|
||||||
|
### Simple Format
|
||||||
|
|
||||||
|
Always displayed after the module is configured:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
post-install-notes: |
|
||||||
|
Thank you for choosing the XYZ Cool Module
|
||||||
|
For Support about this Module call 555-1212
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conditional Format
|
||||||
|
|
||||||
|
Display different messages based on a config question's answer:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
post-install-notes:
|
||||||
|
config_key_name:
|
||||||
|
value1: |
|
||||||
|
Instructions for value1...
|
||||||
|
value2: |
|
||||||
|
Instructions for value2...
|
||||||
|
```
|
||||||
|
|
||||||
|
Values without an entry (e.g., `none`) display nothing. Multiple config keys can each have their own conditional notes.
|
||||||
|
|
||||||
|
### Example: TEA Module
|
||||||
|
|
||||||
|
The TEA module uses the conditional format keyed on `tea_browser_automation`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
post-install-notes:
|
||||||
|
tea_browser_automation:
|
||||||
|
cli: |
|
||||||
|
Playwright CLI Setup:
|
||||||
|
npm install -g @playwright/cli@latest
|
||||||
|
playwright-cli install --skills
|
||||||
|
mcp: |
|
||||||
|
Playwright MCP Setup (two servers):
|
||||||
|
1. playwright — npx @playwright/mcp@latest
|
||||||
|
2. playwright-test — npx playwright run-test-mcp-server
|
||||||
|
auto: |
|
||||||
|
Playwright CLI Setup:
|
||||||
|
...
|
||||||
|
Playwright MCP Setup (two servers):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
When a user selects `auto`, they see both CLI and MCP instructions. When they select `none`, nothing is shown.
|
||||||
|
|
|
||||||
|
|
@ -550,6 +550,8 @@ class ConfigCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.displayModulePostConfigNotes(moduleName, moduleConfig);
|
||||||
|
|
||||||
return newKeys.length > 0 || newStaticKeys.length > 0; // Return true if we had any new fields (interactive or static)
|
return newKeys.length > 0 || newStaticKeys.length > 0; // Return true if we had any new fields (interactive or static)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -923,6 +925,8 @@ class ConfigCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.displayModulePostConfigNotes(moduleName, moduleConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1195,6 +1199,59 @@ class ConfigCollector {
|
||||||
return question;
|
return question;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display post-configuration notes for a module
|
||||||
|
* Shows prerequisite guidance based on collected config values
|
||||||
|
* Reads notes from the module's `post-install-notes` section in module.yaml
|
||||||
|
* Supports two formats:
|
||||||
|
* - Simple string: always displayed
|
||||||
|
* - Object keyed by config field name, with value-specific messages
|
||||||
|
* @param {string} moduleName - Module name
|
||||||
|
* @param {Object} moduleConfig - Parsed module.yaml content
|
||||||
|
*/
|
||||||
|
async displayModulePostConfigNotes(moduleName, moduleConfig) {
|
||||||
|
if (this._silentConfig) return;
|
||||||
|
if (!moduleConfig || !moduleConfig['post-install-notes']) return;
|
||||||
|
|
||||||
|
const notes = moduleConfig['post-install-notes'];
|
||||||
|
const color = await prompts.getColor();
|
||||||
|
|
||||||
|
// Format 1: Simple string - always display
|
||||||
|
if (typeof notes === 'string') {
|
||||||
|
await prompts.log.message('');
|
||||||
|
for (const line of notes.trim().split('\n')) {
|
||||||
|
await prompts.log.message(color.dim(line));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format 2: Conditional on config values
|
||||||
|
if (typeof notes === 'object') {
|
||||||
|
const config = this.collectedConfig[moduleName];
|
||||||
|
if (!config) return;
|
||||||
|
|
||||||
|
let hasOutput = false;
|
||||||
|
for (const [configKey, valueMessages] of Object.entries(notes)) {
|
||||||
|
const selectedValue = config[configKey];
|
||||||
|
if (!selectedValue || !valueMessages[selectedValue]) continue;
|
||||||
|
|
||||||
|
if (hasOutput) await prompts.log.message('');
|
||||||
|
hasOutput = true;
|
||||||
|
|
||||||
|
const message = valueMessages[selectedValue];
|
||||||
|
await prompts.log.message('');
|
||||||
|
for (const line of message.trim().split('\n')) {
|
||||||
|
const trimmedLine = line.trim();
|
||||||
|
if (trimmedLine.endsWith(':') && !trimmedLine.startsWith(' ')) {
|
||||||
|
await prompts.log.info(color.bold(trimmedLine));
|
||||||
|
} else {
|
||||||
|
await prompts.log.message(color.dim(' ' + trimmedLine));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deep merge two objects
|
* Deep merge two objects
|
||||||
* @param {Object} target - Target object
|
* @param {Object} target - Target object
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue