feat(docs): add Getting Started tutorial and simplify build script
- Add comprehensive Getting Started tutorial with installation as Step 1 - Simplify build-docs.js to read directly from docs/ (no consolidation) - Remove backup/restore dance that could corrupt docs folder on build failure - Remove ~150 lines of unused consolidation code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
5d1f820f82
commit
10d99b17e2
|
|
@ -0,0 +1,343 @@
|
||||||
|
---
|
||||||
|
sidebar_label: Getting Started
|
||||||
|
description: Install BMAD and create your first planning document
|
||||||
|
---
|
||||||
|
|
||||||
|
# Getting Started with BMAD
|
||||||
|
|
||||||
|
Learn how to build software with BMAD's AI-powered workflows. By the end of this tutorial, you'll have installed BMAD, initialized a project, and created your first planning document.
|
||||||
|
|
||||||
|
## What You'll Learn
|
||||||
|
|
||||||
|
- How to install and configure BMAD for your IDE
|
||||||
|
- How BMAD organizes work into phases and agents
|
||||||
|
- How to initialize a project and choose a planning track
|
||||||
|
- How to create your first requirements document
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before starting, ensure you have:
|
||||||
|
|
||||||
|
- **Node.js 20+** — Required for the installer
|
||||||
|
- **Git** — Recommended for version control
|
||||||
|
- **AI-powered IDE** — Claude Code, Cursor, Windsurf, or similar
|
||||||
|
- **A project idea** — Even a simple one works for learning
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Install BMAD
|
||||||
|
|
||||||
|
Open a terminal in your project directory and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx bmad-method install
|
||||||
|
```
|
||||||
|
|
||||||
|
The interactive installer guides you through setup:
|
||||||
|
|
||||||
|
### 1.1 Choose Installation Location
|
||||||
|
|
||||||
|
Select where to install BMAD files:
|
||||||
|
|
||||||
|
- **Current directory** — Recommended for new projects
|
||||||
|
- **Subdirectory** — If you want BMAD isolated
|
||||||
|
- **Custom path** — For specific project structures
|
||||||
|
|
||||||
|
### 1.2 Select Your AI Tool
|
||||||
|
|
||||||
|
Choose the IDE you'll be using:
|
||||||
|
|
||||||
|
- Claude Code
|
||||||
|
- Cursor
|
||||||
|
- Windsurf
|
||||||
|
- Other
|
||||||
|
|
||||||
|
The installer configures BMAD to work with your selected tool.
|
||||||
|
|
||||||
|
### 1.3 Choose Modules
|
||||||
|
|
||||||
|
For this tutorial, select **BMM** (BMAD Method) — the core module for software development. You can add other modules later:
|
||||||
|
|
||||||
|
| Module | Purpose |
|
||||||
|
| -------- | ----------------------------------------- |
|
||||||
|
| **BMM** | Core methodology for software development |
|
||||||
|
| **BMGD** | Game development workflows |
|
||||||
|
| **CIS** | Creative intelligence and facilitation |
|
||||||
|
| **BMB** | Building custom agents and workflows |
|
||||||
|
|
||||||
|
### 1.4 Accept Default Configuration
|
||||||
|
|
||||||
|
For your first project, accept the recommended defaults. You can customize settings later in `_bmad/[module]/config.yaml`.
|
||||||
|
|
||||||
|
### 1.5 Verify Installation
|
||||||
|
|
||||||
|
After installation completes, verify by checking your project structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
your-project/
|
||||||
|
├── _bmad/
|
||||||
|
│ ├── bmm/ # Method module
|
||||||
|
│ │ ├── agents/ # Agent files
|
||||||
|
│ │ ├── workflows/ # Workflow files
|
||||||
|
│ │ └── config.yaml # Module config
|
||||||
|
│ └── core/ # Core utilities
|
||||||
|
├── _bmad-output/ # Generated artifacts (created later)
|
||||||
|
└── .claude/ # IDE configuration (if using Claude Code)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Having trouble?** See [Install BMAD](../../how-to/installation/install-bmad.md) for troubleshooting common issues.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Understand How BMAD Works
|
||||||
|
|
||||||
|
Before diving in, let's understand BMAD's core concepts.
|
||||||
|
|
||||||
|
### Phases
|
||||||
|
|
||||||
|
BMAD organizes work into four phases:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||||
|
│ Phase 1 │ │ Phase 2 │ │ Phase 3 │ │ Phase 4 │
|
||||||
|
│ Analysis │ → │ Planning │ → │ Solutioning │ → │Implementation│
|
||||||
|
│ (Optional) │ │ (Required) │ │ (Varies) │ │ (Required) │
|
||||||
|
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||||
|
Brainstorm Requirements Architecture Build code
|
||||||
|
Research PRD or tech-spec Design decisions Story by story
|
||||||
|
```
|
||||||
|
|
||||||
|
### Agents
|
||||||
|
|
||||||
|
Agents are specialized AI personas, each expert in their domain:
|
||||||
|
|
||||||
|
- **Analyst** — Initializes projects, tracks progress, conducts research
|
||||||
|
- **PM** — Creates requirements (PRD or tech-spec)
|
||||||
|
- **UX-Designer** — Designs user interfaces and experiences
|
||||||
|
- **Architect** — Makes technical decisions, designs system architecture
|
||||||
|
- **SM (Scrum Master)** — Manages sprints, creates stories
|
||||||
|
- **DEV** — Implements code, reviews work
|
||||||
|
|
||||||
|
### Workflows
|
||||||
|
|
||||||
|
Workflows are guided processes that agents run. You tell an agent to run a workflow, and it walks you through the process interactively.
|
||||||
|
|
||||||
|
### Planning Tracks
|
||||||
|
|
||||||
|
Based on your project's complexity, BMAD offers three tracks:
|
||||||
|
|
||||||
|
| Track | Best For | Documents Created |
|
||||||
|
| --------------- | ------------------------------------------ | ------------------------------ |
|
||||||
|
| **Quick Flow** | Bug fixes, simple features, clear scope | Tech-spec only |
|
||||||
|
| **BMAD Method** | Products, platforms, complex features | PRD + Architecture + UX |
|
||||||
|
| **Enterprise** | Compliance, multi-tenant, enterprise needs | PRD + Architecture + Security + DevOps |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Initialize Your Project
|
||||||
|
|
||||||
|
Now let's set up your project with BMAD.
|
||||||
|
|
||||||
|
### 3.1 Load the Analyst Agent
|
||||||
|
|
||||||
|
In your IDE, load the Analyst agent. The method depends on your IDE:
|
||||||
|
|
||||||
|
- **Claude Code**: Type `/analyst` or load the agent file directly
|
||||||
|
- **Cursor/Windsurf**: Open the agent file from `_bmad/bmm/agents/`
|
||||||
|
|
||||||
|
Wait for the agent's menu to appear. You'll see a list of available workflows.
|
||||||
|
|
||||||
|
### 3.2 Run the Initialization Workflow
|
||||||
|
|
||||||
|
Tell the agent to initialize your project:
|
||||||
|
|
||||||
|
```
|
||||||
|
Run workflow-init
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use the shorthand:
|
||||||
|
|
||||||
|
```
|
||||||
|
*workflow-init
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Describe Your Project
|
||||||
|
|
||||||
|
The workflow asks you to describe:
|
||||||
|
|
||||||
|
- **Your project and goals** — What are you building? What problem does it solve?
|
||||||
|
- **Existing codebase** — Is this a new project (greenfield) or existing code (brownfield)?
|
||||||
|
- **Size and complexity** — Roughly how big is this? (You can adjust later)
|
||||||
|
|
||||||
|
### 3.4 Choose Your Track
|
||||||
|
|
||||||
|
Based on your description, the workflow suggests a planning track. You can accept the suggestion or choose a different one:
|
||||||
|
|
||||||
|
- Choose **Quick Flow** if you have a clear, bounded task
|
||||||
|
- Choose **BMAD Method** for most new products or features
|
||||||
|
- Choose **Enterprise** if you have compliance or security requirements
|
||||||
|
|
||||||
|
For this tutorial, we'll assume you chose **BMAD Method**.
|
||||||
|
|
||||||
|
### 3.5 Confirm and Create
|
||||||
|
|
||||||
|
Once you confirm, the workflow creates `bmm-workflow-status.yaml` in your project's docs folder. This file tracks your progress through all phases.
|
||||||
|
|
||||||
|
> **Important**: Always start a fresh chat for each workflow. This prevents context limitations from causing issues.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Create Your Requirements Document
|
||||||
|
|
||||||
|
With your project initialized, it's time to create your first planning document — the PRD (Product Requirements Document).
|
||||||
|
|
||||||
|
### 4.1 Start a Fresh Chat
|
||||||
|
|
||||||
|
Close your current chat and start a new one. This ensures the agent has full context capacity for the workflow.
|
||||||
|
|
||||||
|
### 4.2 Load the PM Agent
|
||||||
|
|
||||||
|
Load the PM (Product Manager) agent in your IDE.
|
||||||
|
|
||||||
|
### 4.3 Run the PRD Workflow
|
||||||
|
|
||||||
|
Tell the PM agent:
|
||||||
|
|
||||||
|
```
|
||||||
|
Run prd
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use shortcuts:
|
||||||
|
|
||||||
|
- `*prd`
|
||||||
|
- Select "create-prd" from the menu
|
||||||
|
- Say "Let's create a new PRD"
|
||||||
|
|
||||||
|
### 4.4 Work Through the PRD
|
||||||
|
|
||||||
|
The PM agent guides you through creating your PRD interactively:
|
||||||
|
|
||||||
|
1. **Project overview** — Refine your project description
|
||||||
|
2. **Goals and success metrics** — What does success look like?
|
||||||
|
3. **User personas** — Who uses this product?
|
||||||
|
4. **Functional requirements** — What must the system do?
|
||||||
|
5. **Non-functional requirements** — Performance, security, scalability needs
|
||||||
|
|
||||||
|
Answer the agent's questions thoughtfully. The PRD becomes the foundation for everything that follows.
|
||||||
|
|
||||||
|
### 4.5 Review Your PRD
|
||||||
|
|
||||||
|
When complete, you'll have a `PRD.md` file in your `_bmad-output/` folder. Review it to ensure it captures your vision.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Check Your Progress
|
||||||
|
|
||||||
|
At any point, you can check what to do next.
|
||||||
|
|
||||||
|
### 5.1 Load Any Agent
|
||||||
|
|
||||||
|
Start a fresh chat and load any BMAD agent.
|
||||||
|
|
||||||
|
### 5.2 Ask for Status
|
||||||
|
|
||||||
|
Tell the agent:
|
||||||
|
|
||||||
|
```
|
||||||
|
workflow-status
|
||||||
|
```
|
||||||
|
|
||||||
|
The agent reads your `bmm-workflow-status.yaml` and tells you:
|
||||||
|
|
||||||
|
- Which phase you're in
|
||||||
|
- What workflows are complete
|
||||||
|
- What the next recommended or required step is
|
||||||
|
|
||||||
|
Example response:
|
||||||
|
|
||||||
|
```
|
||||||
|
Phase 2 (Planning) complete:
|
||||||
|
✓ PRD created
|
||||||
|
|
||||||
|
Next recommended steps:
|
||||||
|
- UX Design (optional, if your project has a UI)
|
||||||
|
- Architecture (required for BMAD Method track)
|
||||||
|
Agent: architect
|
||||||
|
Command: create-architecture
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What You've Accomplished
|
||||||
|
|
||||||
|
You've completed the foundation of a BMAD project:
|
||||||
|
|
||||||
|
- Installed BMAD and configured it for your IDE
|
||||||
|
- Initialized a project with your chosen planning track
|
||||||
|
- Created a PRD that defines your product requirements
|
||||||
|
|
||||||
|
Your project now has:
|
||||||
|
|
||||||
|
```
|
||||||
|
your-project/
|
||||||
|
├── _bmad/ # BMAD configuration
|
||||||
|
├── _bmad-output/
|
||||||
|
│ ├── PRD.md # Your requirements document
|
||||||
|
│ └── bmm-workflow-status.yaml # Progress tracking
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Continue building your project by designing your system's technical foundation (required for BMAD Method) and then starting implementation story by story.
|
||||||
|
|
||||||
|
Explore related topics:
|
||||||
|
|
||||||
|
- **[What Are Agents?](../../explanation/core-concepts/what-are-agents.md)** — Deep dive into how agents work
|
||||||
|
- **[What Are Workflows?](../../explanation/core-concepts/what-are-workflows.md)** — Understanding BMAD's workflow system
|
||||||
|
- **[Workflow Reference](../../reference/workflows/index.md)** — Complete list of available workflows
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
Commands you learned in this tutorial:
|
||||||
|
|
||||||
|
| Command | Agent | Purpose |
|
||||||
|
| ---------------- | ------- | ---------------------------------- |
|
||||||
|
| `*workflow-init` | Analyst | Initialize a new project |
|
||||||
|
| `*prd` | PM | Create a Product Requirements Document |
|
||||||
|
| `workflow-status`| Any | Check progress and next steps |
|
||||||
|
|
||||||
|
> **Tip**: Agents are flexible with commands. Menu numbers, shortcuts (`*prd`), or natural language ("Let's create a PRD") all work.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Questions
|
||||||
|
|
||||||
|
**Q: Do I need to create a PRD for every project?**
|
||||||
|
|
||||||
|
Only for BMAD Method and Enterprise tracks. Quick Flow projects use a simpler tech-spec instead.
|
||||||
|
|
||||||
|
**Q: Can I skip Phase 1 (Analysis)?**
|
||||||
|
|
||||||
|
Yes, Phase 1 is optional. If you already know what you're building, start with Phase 2 (Planning).
|
||||||
|
|
||||||
|
**Q: What if I want to brainstorm first?**
|
||||||
|
|
||||||
|
Load the Analyst agent and run `*brainstorm-project` before `workflow-init`.
|
||||||
|
|
||||||
|
**Q: Why start fresh chats for each workflow?**
|
||||||
|
|
||||||
|
Workflows are context-intensive. Reusing chats can cause the AI to hallucinate or lose track of details. Fresh chats ensure maximum context capacity.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- **During workflows**: Agents guide you with questions and explanations
|
||||||
|
- **Check status**: Run `workflow-status` with any agent
|
||||||
|
- **Community**: [Discord](https://discord.gg/gk8jAdXWmj) — #general-dev, #bugs-issues
|
||||||
|
- **Video tutorials**: [BMad Code YouTube](https://www.youtube.com/@BMadCode)
|
||||||
|
|
@ -28,12 +28,6 @@ const REPO_URL = 'https://github.com/bmad-code-org/BMAD-METHOD';
|
||||||
const LLM_MAX_CHARS = 600_000;
|
const LLM_MAX_CHARS = 600_000;
|
||||||
const LLM_WARN_CHARS = 500_000;
|
const LLM_WARN_CHARS = 500_000;
|
||||||
|
|
||||||
const MODULES = ['bmm', 'bmb', 'bmgd', 'cis'];
|
|
||||||
|
|
||||||
// No root docs copied - only docs/ folder content goes to site
|
|
||||||
// README.md, CHANGELOG.md etc. link to GitHub
|
|
||||||
const ROOT_DOCS = [];
|
|
||||||
|
|
||||||
const LLM_EXCLUDE_PATTERNS = ['changelog', 'ide-info/', 'v4-to-v6-upgrade', 'downloads/', 'faq'];
|
const LLM_EXCLUDE_PATTERNS = ['changelog', 'ide-info/', 'v4-to-v6-upgrade', 'downloads/', 'faq'];
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -50,11 +44,11 @@ async function main() {
|
||||||
|
|
||||||
cleanBuildDirectory();
|
cleanBuildDirectory();
|
||||||
|
|
||||||
const consolidatedDir = consolidateDocs();
|
const docsDir = path.join(PROJECT_ROOT, 'docs');
|
||||||
const artifactsDir = await generateArtifacts(consolidatedDir);
|
const artifactsDir = await generateArtifacts(docsDir);
|
||||||
const siteDir = buildDocusaurusSite(artifactsDir);
|
const siteDir = buildDocusaurusSite();
|
||||||
|
|
||||||
printBuildSummary(consolidatedDir, artifactsDir, siteDir);
|
printBuildSummary(docsDir, artifactsDir, siteDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
|
|
@ -66,31 +60,15 @@ main().catch((error) => {
|
||||||
// Pipeline Stages
|
// Pipeline Stages
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
function consolidateDocs() {
|
async function generateArtifacts(docsDir) {
|
||||||
printHeader('Consolidating documentation sources');
|
|
||||||
|
|
||||||
const outputDir = path.join(BUILD_DIR, 'consolidated');
|
|
||||||
fs.mkdirSync(outputDir, { recursive: true });
|
|
||||||
|
|
||||||
copyMainDocs(outputDir);
|
|
||||||
copyRootDocs(outputDir);
|
|
||||||
copyModuleDocs(outputDir);
|
|
||||||
|
|
||||||
const mdCount = countMarkdownFiles(outputDir);
|
|
||||||
console.log();
|
|
||||||
console.log(` \u001B[32m✓\u001B[0m Consolidation complete: ${mdCount} markdown files`);
|
|
||||||
|
|
||||||
return outputDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function generateArtifacts(consolidatedDir) {
|
|
||||||
printHeader('Generating LLM files and download bundles');
|
printHeader('Generating LLM files and download bundles');
|
||||||
|
|
||||||
const outputDir = path.join(BUILD_DIR, 'artifacts');
|
const outputDir = path.join(BUILD_DIR, 'artifacts');
|
||||||
copyDirectory(consolidatedDir, outputDir);
|
fs.mkdirSync(outputDir, { recursive: true });
|
||||||
|
|
||||||
|
// Generate LLM files reading from docs/, output to artifacts/
|
||||||
generateLlmsTxt(outputDir);
|
generateLlmsTxt(outputDir);
|
||||||
generateLlmsFullTxt(outputDir);
|
generateLlmsFullTxt(docsDir, outputDir);
|
||||||
await generateDownloadBundles(outputDir);
|
await generateDownloadBundles(outputDir);
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
|
|
@ -99,21 +77,14 @@ async function generateArtifacts(consolidatedDir) {
|
||||||
return outputDir;
|
return outputDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDocusaurusSite(artifactsDir) {
|
function buildDocusaurusSite() {
|
||||||
printHeader('Building Docusaurus site');
|
printHeader('Building Docusaurus site');
|
||||||
|
|
||||||
const siteDir = path.join(BUILD_DIR, 'site');
|
const siteDir = path.join(BUILD_DIR, 'site');
|
||||||
const mainDocs = path.join(PROJECT_ROOT, 'docs');
|
const artifactsDir = path.join(BUILD_DIR, 'artifacts');
|
||||||
const docsBackup = path.join(BUILD_DIR, 'docs-backup');
|
|
||||||
|
|
||||||
backupAndReplaceDocs(mainDocs, docsBackup, artifactsDir);
|
// Build directly from docs/ - no backup/restore needed
|
||||||
|
|
||||||
try {
|
|
||||||
runDocusaurusBuild(siteDir);
|
runDocusaurusBuild(siteDir);
|
||||||
} finally {
|
|
||||||
restoreDocs(mainDocs, docsBackup);
|
|
||||||
}
|
|
||||||
|
|
||||||
copyArtifactsToSite(artifactsDir, siteDir);
|
copyArtifactsToSite(artifactsDir, siteDir);
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
|
|
@ -122,56 +93,6 @@ function buildDocusaurusSite(artifactsDir) {
|
||||||
return siteDir;
|
return siteDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Documentation Consolidation
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
function copyMainDocs(destDir) {
|
|
||||||
console.log(' → Copying main docs...');
|
|
||||||
const docsDir = path.join(PROJECT_ROOT, 'docs');
|
|
||||||
// Include modules folder - docs now live in docs/modules/ instead of src/modules/*/docs/
|
|
||||||
copyDirectory(docsDir, destDir, ['llms.txt', 'llms-full.txt'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyRootDocs(destDir) {
|
|
||||||
console.log(' → Copying root documentation files...');
|
|
||||||
|
|
||||||
for (const doc of ROOT_DOCS) {
|
|
||||||
const srcPath = path.join(PROJECT_ROOT, doc.src);
|
|
||||||
const destPath = path.join(destDir, doc.dest);
|
|
||||||
|
|
||||||
if (fs.existsSync(srcPath)) {
|
|
||||||
let content = fs.readFileSync(srcPath, 'utf-8');
|
|
||||||
|
|
||||||
if (!content.startsWith('---')) {
|
|
||||||
content = `---\ntitle: "${doc.title}"\n---\n\n${content}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
content = transformMarkdownLinks(content);
|
|
||||||
fs.writeFileSync(destPath, content);
|
|
||||||
console.log(` ${doc.src} → ${doc.dest}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyModuleDocs(destDir) {
|
|
||||||
fs.mkdirSync(path.join(destDir, 'modules'), { recursive: true });
|
|
||||||
|
|
||||||
for (const moduleName of MODULES) {
|
|
||||||
const srcPath = path.join(PROJECT_ROOT, 'src', 'modules', moduleName, 'docs');
|
|
||||||
const moduleDest = path.join(destDir, 'modules', moduleName);
|
|
||||||
|
|
||||||
if (fs.existsSync(srcPath)) {
|
|
||||||
console.log(` → Copying ${moduleName} docs...`);
|
|
||||||
copyDirectory(srcPath, moduleDest, [], false, moduleName);
|
|
||||||
const count = countMarkdownFiles(moduleDest);
|
|
||||||
console.log(` ${count} markdown files`);
|
|
||||||
} else {
|
|
||||||
console.log(` ⚠ WARNING: ${moduleName} docs not found`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// LLM File Generation
|
// LLM File Generation
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -220,11 +141,11 @@ function generateLlmsTxt(outputDir) {
|
||||||
console.log(` Generated llms.txt (${content.length.toLocaleString()} chars)`);
|
console.log(` Generated llms.txt (${content.length.toLocaleString()} chars)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateLlmsFullTxt(outputDir) {
|
function generateLlmsFullTxt(docsDir, outputDir) {
|
||||||
console.log(' → Generating llms-full.txt...');
|
console.log(' → Generating llms-full.txt...');
|
||||||
|
|
||||||
const date = new Date().toISOString().split('T')[0];
|
const date = new Date().toISOString().split('T')[0];
|
||||||
const files = getAllMarkdownFiles(outputDir);
|
const files = getAllMarkdownFiles(docsDir);
|
||||||
|
|
||||||
const output = [
|
const output = [
|
||||||
'# BMAD Method Documentation (Full)',
|
'# BMAD Method Documentation (Full)',
|
||||||
|
|
@ -244,7 +165,7 @@ function generateLlmsFullTxt(outputDir) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullPath = path.join(outputDir, mdPath);
|
const fullPath = path.join(docsDir, mdPath);
|
||||||
try {
|
try {
|
||||||
const content = readMarkdownContent(fullPath);
|
const content = readMarkdownContent(fullPath);
|
||||||
output.push(`<document path="${mdPath}">`, content, '</document>', '');
|
output.push(`<document path="${mdPath}">`, content, '</document>', '');
|
||||||
|
|
@ -352,18 +273,6 @@ async function generatePromptsBundle(downloadsDir) {
|
||||||
// Docusaurus Build
|
// Docusaurus Build
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
function backupAndReplaceDocs(mainDocs, backupDir, artifactsDir) {
|
|
||||||
console.log(' → Preparing docs for Docusaurus...');
|
|
||||||
|
|
||||||
if (fs.existsSync(mainDocs)) {
|
|
||||||
copyDirectory(mainDocs, backupDir);
|
|
||||||
fs.rmSync(mainDocs, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
copyDirectory(artifactsDir, mainDocs, ['llms.txt', 'llms-full.txt']);
|
|
||||||
removeZipFiles(path.join(mainDocs, 'downloads'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function runDocusaurusBuild(siteDir) {
|
function runDocusaurusBuild(siteDir) {
|
||||||
console.log(' → Running docusaurus build...');
|
console.log(' → Running docusaurus build...');
|
||||||
execSync('npx docusaurus build --config website/docusaurus.config.js --out-dir ' + siteDir, {
|
execSync('npx docusaurus build --config website/docusaurus.config.js --out-dir ' + siteDir, {
|
||||||
|
|
@ -372,16 +281,6 @@ function runDocusaurusBuild(siteDir) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreDocs(mainDocs, backupDir) {
|
|
||||||
console.log(' → Restoring original docs...');
|
|
||||||
fs.rmSync(mainDocs, { recursive: true });
|
|
||||||
|
|
||||||
if (fs.existsSync(backupDir)) {
|
|
||||||
copyDirectory(backupDir, mainDocs);
|
|
||||||
fs.rmSync(backupDir, { recursive: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyArtifactsToSite(artifactsDir, siteDir) {
|
function copyArtifactsToSite(artifactsDir, siteDir) {
|
||||||
console.log(' → Copying artifacts to site...');
|
console.log(' → Copying artifacts to site...');
|
||||||
|
|
||||||
|
|
@ -394,26 +293,16 @@ function copyArtifactsToSite(artifactsDir, siteDir) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeZipFiles(dir) {
|
|
||||||
if (!fs.existsSync(dir)) return;
|
|
||||||
|
|
||||||
for (const file of fs.readdirSync(dir)) {
|
|
||||||
if (file.endsWith('.zip')) {
|
|
||||||
fs.unlinkSync(path.join(dir, file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Build Summary
|
// Build Summary
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
function printBuildSummary(consolidatedDir, artifactsDir, siteDir) {
|
function printBuildSummary(docsDir, artifactsDir, siteDir) {
|
||||||
console.log();
|
console.log();
|
||||||
printBanner('Build Complete!');
|
printBanner('Build Complete!');
|
||||||
console.log();
|
console.log();
|
||||||
console.log('Build artifacts:');
|
console.log('Build artifacts:');
|
||||||
console.log(` Consolidated docs: ${consolidatedDir}`);
|
console.log(` Source docs: ${docsDir}`);
|
||||||
console.log(` Generated files: ${artifactsDir}`);
|
console.log(` Generated files: ${artifactsDir}`);
|
||||||
console.log(` Final site: ${siteDir}`);
|
console.log(` Final site: ${siteDir}`);
|
||||||
console.log();
|
console.log();
|
||||||
|
|
@ -461,7 +350,7 @@ function cleanBuildDirectory() {
|
||||||
fs.mkdirSync(BUILD_DIR, { recursive: true });
|
fs.mkdirSync(BUILD_DIR, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyDirectory(src, dest, exclude = [], transformMd = false, moduleName = null) {
|
function copyDirectory(src, dest, exclude = []) {
|
||||||
if (!fs.existsSync(src)) return false;
|
if (!fs.existsSync(src)) return false;
|
||||||
fs.mkdirSync(dest, { recursive: true });
|
fs.mkdirSync(dest, { recursive: true });
|
||||||
|
|
||||||
|
|
@ -472,12 +361,7 @@ function copyDirectory(src, dest, exclude = [], transformMd = false, moduleName
|
||||||
const destPath = path.join(dest, entry.name);
|
const destPath = path.join(dest, entry.name);
|
||||||
|
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
copyDirectory(srcPath, destPath, exclude, transformMd, moduleName);
|
copyDirectory(srcPath, destPath, exclude);
|
||||||
} else if (entry.name.endsWith('.md')) {
|
|
||||||
// Always transform markdown links, use module context if provided
|
|
||||||
let content = fs.readFileSync(srcPath, 'utf-8');
|
|
||||||
content = transformMarkdownLinks(content, moduleName);
|
|
||||||
fs.writeFileSync(destPath, content);
|
|
||||||
} else {
|
} else {
|
||||||
fs.copyFileSync(srcPath, destPath);
|
fs.copyFileSync(srcPath, destPath);
|
||||||
}
|
}
|
||||||
|
|
@ -485,102 +369,6 @@ function copyDirectory(src, dest, exclude = [], transformMd = false, moduleName
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformMarkdownLinks(content, moduleName = null) {
|
|
||||||
// Transform HTML img src attributes for module docs images
|
|
||||||
content = content.replaceAll(/src="\.\/src\/modules\/([^/]+)\/docs\/images\/([^"]+)"/g, (match, mod, file) => {
|
|
||||||
return `src="./modules/${mod}/images/${file}"`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return content.replaceAll(/\]\(([^)]+)\)/g, (match, url) => {
|
|
||||||
// src/modules/{mod}/docs/{path}.md → ./modules/{mod}/{path}.md
|
|
||||||
// Keeps .md - Docusaurus handles .md → page conversion
|
|
||||||
const docsMatch = url.match(/^\.\.?\/src\/modules\/([^/]+)\/docs\/(.+\.md)$/);
|
|
||||||
if (docsMatch) return `](./modules/${docsMatch[1]}/${docsMatch[2]})`;
|
|
||||||
|
|
||||||
// src/modules/{mod}/docs/ → ./modules/{mod}/
|
|
||||||
const docsDirMatch = url.match(/^\.\.?\/src\/modules\/([^/]+)\/docs\/$/);
|
|
||||||
if (docsDirMatch) return `](./modules/${docsDirMatch[1]}/)`;
|
|
||||||
|
|
||||||
// src/modules/{mod}/docs/images/{file} → ./modules/{mod}/images/{file}
|
|
||||||
const docsImageMatch = url.match(/^\.\.?\/src\/modules\/([^/]+)\/docs\/images\/(.+)$/);
|
|
||||||
if (docsImageMatch) return `](./modules/${docsImageMatch[1]}/images/${docsImageMatch[2]})`;
|
|
||||||
|
|
||||||
// src/modules/{mod}/README.md → GitHub (not in docs folder)
|
|
||||||
const readmeMatch = url.match(/^\.\.?\/src\/modules\/([^/]+)\/README\.md$/i);
|
|
||||||
if (readmeMatch) return `](${REPO_URL}/blob/main/src/modules/${readmeMatch[1]}/README.md)`;
|
|
||||||
|
|
||||||
// src/modules/* (non-docs) → GitHub
|
|
||||||
const srcMatch = url.match(/^\.\.?\/src\/modules\/(.+)$/);
|
|
||||||
if (srcMatch) return `](${REPO_URL}/tree/main/src/modules/${srcMatch[1]})`;
|
|
||||||
|
|
||||||
// Relative paths escaping docs/ folder → GitHub (when module context is known)
|
|
||||||
// e.g., ../workflows/foo/bar.md from within docs/ → src/modules/{mod}/workflows/foo/bar.md
|
|
||||||
if (moduleName) {
|
|
||||||
const relativeEscapeMatch = url.match(/^\.\.\/([^.][^)]+)$/);
|
|
||||||
if (relativeEscapeMatch && !relativeEscapeMatch[1].startsWith('src/')) {
|
|
||||||
const relativePath = relativeEscapeMatch[1];
|
|
||||||
return `](${REPO_URL}/blob/main/src/modules/${moduleName}/${relativePath})`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ./docs/{path}.md → ./{path}.md (docs folder contents are at root in build)
|
|
||||||
// Keeps .md - Docusaurus handles .md → page conversion
|
|
||||||
const rootDocsMatch = url.match(/^\.\/docs\/(.+\.md)$/);
|
|
||||||
if (rootDocsMatch) return `](./${rootDocsMatch[1]})`;
|
|
||||||
|
|
||||||
// Root docs → GitHub (not part of docs site)
|
|
||||||
if (url === '../README.md' || url === './README.md' || url === './project-readme') {
|
|
||||||
return `](${REPO_URL}/blob/main/README.md)`;
|
|
||||||
}
|
|
||||||
if (url === '../CHANGELOG.md' || url === './CHANGELOG.md' || url === './changelog') {
|
|
||||||
return `](${REPO_URL}/blob/main/CHANGELOG.md)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Root files → GitHub (CONTRIBUTING, LICENSE, CODE_OF_CONDUCT, etc.)
|
|
||||||
const contributingMatch = url.match(/^(\.\.\/)?CONTRIBUTING\.md(#.*)?$/);
|
|
||||||
if (contributingMatch) {
|
|
||||||
const anchor = contributingMatch[2] || '';
|
|
||||||
return `](${REPO_URL}/blob/main/CONTRIBUTING.md${anchor})`;
|
|
||||||
}
|
|
||||||
if (url === 'LICENSE' || url === '../LICENSE') {
|
|
||||||
return `](${REPO_URL}/blob/main/LICENSE)`;
|
|
||||||
}
|
|
||||||
if (url === '.github/CODE_OF_CONDUCT.md' || url === '../.github/CODE_OF_CONDUCT.md') {
|
|
||||||
return `](${REPO_URL}/blob/main/.github/CODE_OF_CONDUCT.md)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other root .md files → GitHub
|
|
||||||
const rootFileMatch = url.match(/^\.\.\/([A-Z][^/]+\.md)$/);
|
|
||||||
if (rootFileMatch) return `](${REPO_URL}/blob/main/${rootFileMatch[1]})`;
|
|
||||||
|
|
||||||
// Cross-module doc links: ../../{mod}/docs/{path}.md → ../{mod}/{path}.md
|
|
||||||
// Fixes path structure but keeps .md (Docusaurus handles .md → page conversion)
|
|
||||||
const crossModuleDocsMatch = url.match(/^\.\.\/\.\.\/([^/]+)\/docs\/(.+\.md)$/);
|
|
||||||
if (crossModuleDocsMatch) return `](../${crossModuleDocsMatch[1]}/${crossModuleDocsMatch[2]})`;
|
|
||||||
|
|
||||||
// Root-level folders (samples/) → GitHub
|
|
||||||
const rootFolderMatch = url.match(/^\.\.\/((samples)\/.*)/);
|
|
||||||
if (rootFolderMatch) return `](${REPO_URL}/blob/main/${rootFolderMatch[1]})`;
|
|
||||||
|
|
||||||
return match;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function countMarkdownFiles(dir) {
|
|
||||||
let count = 0;
|
|
||||||
if (!fs.existsSync(dir)) return 0;
|
|
||||||
|
|
||||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
||||||
const fullPath = path.join(dir, entry.name);
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
count += countMarkdownFiles(fullPath);
|
|
||||||
} else if (entry.name.endsWith('.md')) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createZipArchive(sourceDir, outputPath, exclude = []) {
|
function createZipArchive(sourceDir, outputPath, exclude = []) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const output = fs.createWriteStream(outputPath);
|
const output = fs.createWriteStream(outputPath);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue