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_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'];
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -50,11 +44,11 @@ async function main() {
|
|||
|
||||
cleanBuildDirectory();
|
||||
|
||||
const consolidatedDir = consolidateDocs();
|
||||
const artifactsDir = await generateArtifacts(consolidatedDir);
|
||||
const siteDir = buildDocusaurusSite(artifactsDir);
|
||||
const docsDir = path.join(PROJECT_ROOT, 'docs');
|
||||
const artifactsDir = await generateArtifacts(docsDir);
|
||||
const siteDir = buildDocusaurusSite();
|
||||
|
||||
printBuildSummary(consolidatedDir, artifactsDir, siteDir);
|
||||
printBuildSummary(docsDir, artifactsDir, siteDir);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
|
|
@ -66,31 +60,15 @@ main().catch((error) => {
|
|||
// Pipeline Stages
|
||||
// =============================================================================
|
||||
|
||||
function consolidateDocs() {
|
||||
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) {
|
||||
async function generateArtifacts(docsDir) {
|
||||
printHeader('Generating LLM files and download bundles');
|
||||
|
||||
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);
|
||||
generateLlmsFullTxt(outputDir);
|
||||
generateLlmsFullTxt(docsDir, outputDir);
|
||||
await generateDownloadBundles(outputDir);
|
||||
|
||||
console.log();
|
||||
|
|
@ -99,21 +77,14 @@ async function generateArtifacts(consolidatedDir) {
|
|||
return outputDir;
|
||||
}
|
||||
|
||||
function buildDocusaurusSite(artifactsDir) {
|
||||
function buildDocusaurusSite() {
|
||||
printHeader('Building Docusaurus site');
|
||||
|
||||
const siteDir = path.join(BUILD_DIR, 'site');
|
||||
const mainDocs = path.join(PROJECT_ROOT, 'docs');
|
||||
const docsBackup = path.join(BUILD_DIR, 'docs-backup');
|
||||
|
||||
backupAndReplaceDocs(mainDocs, docsBackup, artifactsDir);
|
||||
|
||||
try {
|
||||
runDocusaurusBuild(siteDir);
|
||||
} finally {
|
||||
restoreDocs(mainDocs, docsBackup);
|
||||
}
|
||||
const artifactsDir = path.join(BUILD_DIR, 'artifacts');
|
||||
|
||||
// Build directly from docs/ - no backup/restore needed
|
||||
runDocusaurusBuild(siteDir);
|
||||
copyArtifactsToSite(artifactsDir, siteDir);
|
||||
|
||||
console.log();
|
||||
|
|
@ -122,56 +93,6 @@ function buildDocusaurusSite(artifactsDir) {
|
|||
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
|
||||
// =============================================================================
|
||||
|
|
@ -220,11 +141,11 @@ function generateLlmsTxt(outputDir) {
|
|||
console.log(` Generated llms.txt (${content.length.toLocaleString()} chars)`);
|
||||
}
|
||||
|
||||
function generateLlmsFullTxt(outputDir) {
|
||||
function generateLlmsFullTxt(docsDir, outputDir) {
|
||||
console.log(' → Generating llms-full.txt...');
|
||||
|
||||
const date = new Date().toISOString().split('T')[0];
|
||||
const files = getAllMarkdownFiles(outputDir);
|
||||
const files = getAllMarkdownFiles(docsDir);
|
||||
|
||||
const output = [
|
||||
'# BMAD Method Documentation (Full)',
|
||||
|
|
@ -244,7 +165,7 @@ function generateLlmsFullTxt(outputDir) {
|
|||
continue;
|
||||
}
|
||||
|
||||
const fullPath = path.join(outputDir, mdPath);
|
||||
const fullPath = path.join(docsDir, mdPath);
|
||||
try {
|
||||
const content = readMarkdownContent(fullPath);
|
||||
output.push(`<document path="${mdPath}">`, content, '</document>', '');
|
||||
|
|
@ -352,18 +273,6 @@ async function generatePromptsBundle(downloadsDir) {
|
|||
// 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) {
|
||||
console.log(' → Running docusaurus build...');
|
||||
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) {
|
||||
console.log(' → Copying artifacts to site...');
|
||||
|
||||
|
|
@ -394,28 +293,18 @@ 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
|
||||
// =============================================================================
|
||||
|
||||
function printBuildSummary(consolidatedDir, artifactsDir, siteDir) {
|
||||
function printBuildSummary(docsDir, artifactsDir, siteDir) {
|
||||
console.log();
|
||||
printBanner('Build Complete!');
|
||||
console.log();
|
||||
console.log('Build artifacts:');
|
||||
console.log(` Consolidated docs: ${consolidatedDir}`);
|
||||
console.log(` Generated files: ${artifactsDir}`);
|
||||
console.log(` Final site: ${siteDir}`);
|
||||
console.log(` Source docs: ${docsDir}`);
|
||||
console.log(` Generated files: ${artifactsDir}`);
|
||||
console.log(` Final site: ${siteDir}`);
|
||||
console.log();
|
||||
console.log(`Deployable output: ${siteDir}/`);
|
||||
console.log();
|
||||
|
|
@ -461,7 +350,7 @@ function cleanBuildDirectory() {
|
|||
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;
|
||||
fs.mkdirSync(dest, { recursive: true });
|
||||
|
||||
|
|
@ -472,12 +361,7 @@ function copyDirectory(src, dest, exclude = [], transformMd = false, moduleName
|
|||
const destPath = path.join(dest, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
copyDirectory(srcPath, destPath, exclude, transformMd, moduleName);
|
||||
} 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);
|
||||
copyDirectory(srcPath, destPath, exclude);
|
||||
} else {
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
}
|
||||
|
|
@ -485,102 +369,6 @@ function copyDirectory(src, dest, exclude = [], transformMd = false, moduleName
|
|||
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 = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const output = fs.createWriteStream(outputPath);
|
||||
|
|
|
|||
Loading…
Reference in New Issue