diff --git a/README.md b/README.md index 49a83e74..7f73e30d 100644 --- a/README.md +++ b/README.md @@ -1,237 +1,75 @@ -# BMad Method & BMad Core +# BMAD Method -[](https://www.npmjs.com/package/bmad-method) -[](https://www.npmjs.com/package/bmad-method) +[](https://www.npmjs.com/package/bmad-method) [](LICENSE) [](https://nodejs.org) [](https://discord.gg/gk8jAdXWmj) ---- +**Build More, Architect Dreams** β An AI-driven agile development framework with 21 specialized agents, 50+ guided workflows, and scale-adaptive intelligence that adjusts from bug fixes to enterprise systems. -
-
-
- Complete BMad Method workflow showing all phases, agents, and decision points -
- -## π Get Started in 3 Steps - -### 1. Install BMad Method +**Prerequisites**: [Node.js](https://nodejs.org) v20+ ```bash -# Install v6 RECOMMENDED npx bmad-method@alpha install ``` +Follow the installer prompts to configure your project. Then run: + ```bash -# Install v4 Legacy (not recommended if starting fresh) -npx bmad-method install -# OR -npx bmad-method@latest install -``` - - -### 2. Initialize Your Project - -Load any agent in your IDE and run: - -``` *workflow-init ``` -This analyzes your project and recommends the right workflow track. +This analyzes your project and recommends a track: -### 3. Choose Your Track +| Track | Best For | Time to First Story | +| --------------- | ------------------------- | ------------------- | +| **Quick Flow** | Bug fixes, small features | ~5 minutes | +| **BMad Method** | Products and platforms | ~15 minutes | +| **Enterprise** | Compliance-heavy systems | ~30 minutes | -BMad Method adapts to your needs with three intelligent tracks: +## Modules -| Track | Use For | Planning | Time to Start | -| ----------------- | ------------------------- | ----------------------- | ------------- | -| **β‘ Quick Flow** | Bug fixes, small features | Tech spec only | < 5 minutes | -| **π BMad Method** | Products, platforms | PRD + Architecture + UX | < 15 minutes | -| **π’ Enterprise** | Compliance, scale | Full governance suite | < 30 minutes | +| Module | Purpose | +| ------------------------------------- | -------------------------------------------------------- | +| **BMad Method (BMM)** | Core agile development with 34 workflows across 4 phases | +| **BMad Builder (BMB)** | Create custom agents and domain-specific modules | +| **Creative Intelligence Suite (CIS)** | Innovation, brainstorming, and problem-solving | -> **Not sure?** Run `*workflow-init` and let BMad analyze your project goal. +## Documentation -## π How It Works: 4-Phase Methodology +**[Full Documentation](http://docs.bmad-method.org)** β Tutorials, how-to guides, concepts, and reference -BMad Method guides you through a proven development lifecycle: +- [Getting Started Tutorial](http://docs.bmad-method.org/tutorials/getting-started/getting-started-bmadv6/) +- [Upgrading from Previous Versions](http://docs.bmad-method.org/how-to/installation/upgrade-to-v6/) -1. **π Analysis** (Optional) - Brainstorm, research, and explore solutions -2. **π Planning** - Create PRDs, tech specs, or game design documents -3. **ποΈ Solutioning** - Design architecture, UX, and technical approach -4. **β‘ Implementation** - Story-driven development with continuous validation +## Community -Each phase has specialized workflows and agents working together to deliver exceptional results. +- [Discord](https://discord.gg/gk8jAdXWmj) β Get help, share ideas, collaborate +- [YouTube](https://www.youtube.com/@BMadCode) β Video tutorials and updates +- [GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) β Bug reports and feature requests +- [Discussions](https://github.com/bmad-code-org/BMAD-METHOD/discussions) β Community conversations -## π€ Meet Your Team +## Contributing -**12 Specialized Agents** working in concert: +We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. -| Development | Architecture | Product | Leadership | -| ----------- | -------------- | ----------- | ------------ | -| Developer | Architect | PM | Scrum Master | -| UX Designer | Test Architect | Analyst | BMad Master | -| | | Tech Writer | | +## License -**Test Architect** integrates with `@seontechnologies/playwright-utils` for production-ready web app fixture-based utilities. - -Each agent brings deep expertise and can be customized to match your team's style. - -## π¦ What's Included - -### Official Modules - -- **BMad Method (BMM)** - Complete agile development framework - - 12 specialized agents - - 34 workflows across 4 phases - - Stand Along Quick Spec Flow for a streamlined simple implementation process - - [β Documentation Hub](http://docs.bmad-method.org/explanation/bmm/) - -- **BMad Builder (BMB)** - Create custom agents and workflows - - Build anything from simple agents to complex modules - - Create domain-specific solutions (legal, medical, finance, education) - - [β Builder Guide](http://docs.bmad-method.org/explanation/bmad-builder/) - -- **Creative Intelligence Suite (CIS)** - Innovation & problem-solving - - Brainstorming, design thinking, storytelling - - 5 creative facilitation workflows - - [β Creative Workflows](http://docs.bmad-method.org/explanation/creative-intelligence/) - -### Key Features - -- **π¨ Customizable Agents** - Modify personalities, expertise, and communication styles -- **π Multi-Language Support** - Separate settings for communication and code output -- **π Document Sharding** - 90% token savings for large projects -- **π Update-Safe** - Your customizations persist through updates -- **π Web Bundles** - Use in ChatGPT, Claude Projects, or Gemini Gems - -## π Documentation - -### Quick Links - -- **[Quick Start Guide](http://docs.bmad-method.org/tutorials/getting-started/getting-started-bmadv6/)** - 15-minute introduction -- **[Complete BMM Documentation](http://docs.bmad-method.org/explanation/bmm/)** - All guides and references -- **[Agent Customization](http://docs.bmad-method.org/how-to/customization/customize-agents/)** - Personalize your agents -- **[All Documentation](http://docs.bmad-method.org/)** - Complete documentation index - -### For v4 Users - -- **[v4 Documentation](https://github.com/bmad-code-org/BMAD-METHOD/tree/V4/docs)** -- **[v4 to v6 Upgrade Guide](http://docs.bmad-method.org/how-to/installation/upgrade-to-v6/)** - -## π¬ Community & Support - -- **[Discord Community](https://discord.gg/gk8jAdXWmj)** - Get help, share projects -- **[GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues)** - Report bugs, request features -- **[YouTube Channel](https://www.youtube.com/@BMadCode)** - Video tutorials and demos -- **[Web Bundles](https://bmad-code-org.github.io/bmad-bundles/)** - Pre-built agent bundles (Currently not functioning, reworking soon) -- **[Code of Conduct](.github/CODE_OF_CONDUCT.md)** - Community guidelines - -## π οΈ Development - -If you would like to contribute, first check the [CONTRIBUTING.md](CONTRIBUTING.md) for full development guidelines. - -## What's New in v6 - -**v6 represents a complete architectural revolution from v4:** - -### π Major Upgrades - -- **BMad Core Framework** - Modular architecture enabling custom domain solutions -- **Scale-Adaptive Intelligence** - Automatic adjustment from bug fixes to enterprise -- **Visual Workflows** - Beautiful SVG diagrams showing complete methodology -- **BMad Builder Module** - Create and share your own AI agent teams -- **50+ Workflows** - Up from 20 in v4, covering every development scenario -- **19 Specialized Agents** - Enhanced with customizable personalities and expertise -- **Update-Safe Customization** - Your configs persist through all updates -- **Web Bundles** - Use agents in ChatGPT, Claude, and Gemini -- **Multi-Language Support** - Separate settings for communication and code -- **Document Sharding** - 90% token savings for large projects - -### π For v4 Users - -- **[Comprehensive Upgrade Guide](http://docs.bmad-method.org/how-to/installation/upgrade-to-v6/)** - Step-by-step migration -- **[v4 Documentation Archive](https://github.com/bmad-code-org/BMAD-METHOD/tree/V4)** - Legacy reference -- Backwards compatibility where possible -- Smooth migration path with installer detection - -## π License - -MIT License - See [LICENSE](LICENSE) for details. - -**Trademarks:** BMadβ’ and BMAD-METHODβ’ are trademarks of BMad Code, LLC. - -Supported by:
-
-
-
-
- Built with β€οΈ for the human-AI collaboration community -
+[](https://github.com/bmad-code-org/BMAD-METHOD/graphs/contributors) diff --git a/docs/explanation/features/web-bundles.md b/docs/explanation/features/web-bundles.md index aeef17e1..3cf6212c 100644 --- a/docs/explanation/features/web-bundles.md +++ b/docs/explanation/features/web-bundles.md @@ -33,5 +33,3 @@ Web bundles package BMad agents as self-contained files that work in Gemini Gems - Some quality reduction vs local usage - Less convenient than full local installation - Limited to agent capabilities (no workflow file access) - -[β Back to Core Concepts](../index.md) diff --git a/docs/how-to/customization/index.md b/docs/how-to/customization/index.md index 12c3eca1..c66f4f34 100644 --- a/docs/how-to/customization/index.md +++ b/docs/how-to/customization/index.md @@ -25,5 +25,3 @@ Replace or extend workflow steps to create tailored processes. (Coming soon) --- **Next:** Read the [Agent Customization Guide](./customize-agents.md) to start personalizing your agents. - -[β Back to Core Concepts](../index.md) diff --git a/docs/index.md b/docs/index.md index a43bddda..484852d4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,8 +1,8 @@ --- -title: Welcome to BMad +title: Welcome to the BMad Method --- -BMad (**B**uild **M**ore, **A**rchitect **D**reams) is an AI-driven development framework that helps you build software faster and smarter. It provides specialized AI agents, guided workflows, and intelligent planning that adapts to your project's complexityβwhether you're fixing a bug or building an enterprise platform. +The BMad Method (**B**reakthrough **M**ethod of **A**gile AI **D**riven Development) is an AI-driven development framework that helps you build software faster and smarter. It provides specialized AI agents, guided workflows, and intelligent planning that adapts to your project's complexityβwhether you're fixing a bug or building an enterprise platform. If you're comfortable working with AI coding assistants like Claude, Cursor, or GitHub Copilot, you're ready to get started. @@ -12,8 +12,7 @@ If you're comfortable working with AI coding assistants like Claude, Cursor, or The fastest way to understand BMad is to try it. Choose a tutorial to walk through your first project in about 10 minutes. -- **[Get Started with v4 (Stable)](./tutorials/getting-started/getting-started-bmadv4.md)** β Production-ready version with battle-tested workflows -- **[Try v6 (Alpha)](./tutorials/getting-started/getting-started-bmadv6.md)** β Latest features, still in active development +- **[Get Started with BMad](./tutorials/getting-started/getting-started-bmadv6.md)** β Latest features, still in active development :::tip[Already familiar with AI-assisted development?] Feel free to skip around. Use the sidebar to jump to any topic, or check out [What Are Agents?](./explanation/core-concepts/what-are-agents.md) to understand how BMad organizes its AI personas. @@ -25,12 +24,12 @@ Feel free to skip around. Use the sidebar to jump to any topic, or check out [Wh These docs are organized into four sections based on what you're trying to do: -| Section | Purpose | -|---------|---------| -| **[Tutorials](./tutorials/index.md)** | Learning-oriented. Step-by-step guides that walk you through building something. Start here if you're new. | -| **[How-To Guides](./how-to/index.md)** | Task-oriented. Practical guides for solving specific problems. "How do I customize an agent?" lives here. | -| **[Explanation](./explanation/index.md)** | Understanding-oriented. Deep dives into concepts and architecture. Read when you want to know *why*. | -| **[Reference](./reference/index.md)** | Information-oriented. Technical specifications for agents, workflows, and configuration. | +| Section | Purpose | +| ----------------- | ---------------------------------------------------------------------------------------------------------- | +| **Tutorials** | Learning-oriented. Step-by-step guides that walk you through building something. Start here if you're new. | +| **How-To Guides** | Task-oriented. Practical guides for solving specific problems. "How do I customize an agent?" lives here. | +| **Explanation** | Understanding-oriented. Deep dives into concepts and architecture. Read when you want to know *why*. | +| **Reference** | Information-oriented. Technical specifications for agents, workflows, and configuration. | --- @@ -61,5 +60,4 @@ Get help, share what you're building, or contribute to BMad: Ready to dive in? Pick a tutorial and start building. -- **[Get Started with v4 (Stable)](./tutorials/getting-started/getting-started-bmadv4.md)** β Recommended for production projects -- **[Try v6 (Alpha)](./tutorials/getting-started/getting-started-bmadv6.md)** β Explore the latest features +- **[Get Started with BMadv6](./tutorials/getting-started/getting-started-bmadv6.md)** β Explore the latest features diff --git a/docs/tutorials/getting-started/getting-started-bmadv6.md b/docs/tutorials/getting-started/getting-started-bmadv6.md index 644e822d..6b8b6e11 100644 --- a/docs/tutorials/getting-started/getting-started-bmadv6.md +++ b/docs/tutorials/getting-started/getting-started-bmadv6.md @@ -1,15 +1,14 @@ --- -title: "Getting Started with BMad v6 Alpha" -description: Install BMad v6 Alpha and build your first project +title: "Getting Started with the BMad Method" +description: Install BMad and build your first project --- +**Upgrading from previous versions?** See the [Upgrade Guide](../../how-to/installation/upgrade-to-v6.md) instead. + +--- Build software faster using AI-powered workflows with specialized agents that guide you through planning, architecture, and implementation. -:::caution[Alpha Software] -BMad v6 is currently in **alpha**. Expect breaking changes, incomplete features, and evolving documentation. For a stable experience, use the [BMad v4 tutorial](./getting-started-bmadv4.md) instead. -::: - ## What You'll Learn - Install and initialize BMad Method for a new project @@ -36,12 +35,12 @@ BMad v6 is currently in **alpha**. Expect breaking changes, incomplete features, BMad helps you build software through guided workflows with specialized AI agents. The process follows four phases: -| Phase | Name | What Happens | -|-------|------|--------------| -| 1 | Analysis | Brainstorming, research, product brief *(optional)* | -| 2 | Planning | Create requirements (PRD or tech-spec) | -| 3 | Solutioning | Design architecture *(BMad Method/Enterprise only)* | -| 4 | Implementation | Build epic by epic, story by story | +| Phase | Name | What Happens | +| ----- | -------------- | --------------------------------------------------- | +| 1 | Analysis | Brainstorming, research, product brief *(optional)* | +| 2 | Planning | Create requirements (PRD or tech-spec) | +| 3 | Solutioning | Design architecture *(BMad Method/Enterprise only)* | +| 4 | Implementation | Build epic by epic, story by story |  @@ -49,11 +48,11 @@ BMad helps you build software through guided workflows with specialized AI agent Based on your project's complexity, BMad offers three planning tracks: -| Track | Best For | Documents Created | -|-------|----------|-------------------| -| **Quick Flow** | Bug fixes, simple features, clear scope (1-15 stories) | Tech-spec only | -| **BMad Method** | Products, platforms, complex features (10-50+ stories) | PRD + Architecture + UX | -| **Enterprise** | Compliance, multi-tenant systems (30+ stories) | PRD + Architecture + Security + DevOps | +| Track | Best For | Documents Created | +| --------------- | ------------------------------------------------------ | -------------------------------------- | +| **Quick Flow** | Bug fixes, simple features, clear scope (1-15 stories) | Tech-spec only | +| **BMad Method** | Products, platforms, complex features (10-50+ stories) | PRD + Architecture + UX | +| **Enterprise** | Compliance, multi-tenant systems (30+ stories) | PRD + Architecture + Security + DevOps | :::note Story counts are guidance, not definitions. Choose your track based on planning needs, not story math. @@ -166,12 +165,12 @@ Load the **SM agent** and run `sprint-planning`. This creates `sprint-status.yam For each story, repeat this cycle with fresh chats: -| Step | Agent | Workflow | Purpose | -|------|-------|----------|---------| -| 1 | SM | `create-story` | Create story file from epic | -| 2 | DEV | `dev-story` | Implement the story | -| 3 | TEA | `automate` | Generate guardrail tests *(optional)* | -| 4 | DEV | `code-review` | Quality validation *(recommended)* | +| Step | Agent | Workflow | Purpose | +| ---- | ----- | -------------- | ------------------------------------- | +| 1 | SM | `create-story` | Create story file from epic | +| 2 | DEV | `dev-story` | Implement the story | +| 3 | TEA | `automate` | Generate guardrail tests *(optional)* | +| 4 | DEV | `code-review` | Quality validation *(recommended)* | After completing all stories in an epic, load the **SM agent** and run `retrospective`. @@ -200,18 +199,18 @@ your-project/ ## Quick Reference -| Command | Agent | Purpose | -|---------|-------|---------| -| `*workflow-init` | Analyst | Initialize a new project | -| `*workflow-status` | Any | Check progress and next steps | -| `*prd` | PM | Create Product Requirements Document | -| `*create-architecture` | Architect | Create architecture document | -| `*create-epics-and-stories` | PM | Break down PRD into epics | -| `*implementation-readiness` | Architect | Validate planning cohesion | -| `*sprint-planning` | SM | Initialize sprint tracking | -| `*create-story` | SM | Create a story file | -| `*dev-story` | DEV | Implement a story | -| `*code-review` | DEV | Review implemented code | +| Command | Agent | Purpose | +| --------------------------- | --------- | ------------------------------------ | +| `*workflow-init` | Analyst | Initialize a new project | +| `*workflow-status` | Any | Check progress and next steps | +| `*prd` | PM | Create Product Requirements Document | +| `*create-architecture` | Architect | Create architecture document | +| `*create-epics-and-stories` | PM | Break down PRD into epics | +| `*implementation-readiness` | Architect | Validate planning cohesion | +| `*sprint-planning` | SM | Initialize sprint tracking | +| `*create-story` | SM | Create a story file | +| `*dev-story` | DEV | Implement a story | +| `*code-review` | DEV | Review implemented code | ## Common Questions diff --git a/tools/audit-doc-links.js b/tools/audit-doc-links.js new file mode 100644 index 00000000..c028e90e --- /dev/null +++ b/tools/audit-doc-links.js @@ -0,0 +1,341 @@ +/** + * Documentation Link Auditor + * + * Scans markdown files in docs/ and: + * - Identifies broken relative links + * - Attempts to find where files may have moved + * - Generates a report with auto-fix suggestions + * - Outputs JSON for the fixer script to consume + * + * Usage: node tools/audit-doc-links.js + */ + +const { readFileSync, writeFileSync, existsSync } = require('node:fs'); +const { resolve, dirname, join, normalize, relative, basename } = require('node:path'); +const { glob } = require('glob'); + +const DOCS_DIR = resolve(process.cwd(), 'docs'); +const REPORT_PATH = resolve(__dirname, '.link-audit-report.json'); + +// Regex to match markdown links: [text](path) +const LINK_PATTERN = /\[([^\]]*)\]\(([^)]+)\)/g; + +// Colors for console output +const colors = { + reset: '\u001B[0m', + red: '\u001B[31m', + green: '\u001B[32m', + yellow: '\u001B[33m', + cyan: '\u001B[36m', + dim: '\u001B[2m', +}; + +/** + * Determines whether a link should be ignored during validation. + */ +function shouldIgnoreLink(link) { + return ( + link.startsWith('http://') || + link.startsWith('https://') || + link.startsWith('mailto:') || + link.startsWith('tel:') || + link.startsWith('/') || // Absolute paths handled by Astro routing + link.startsWith('#') // Same-file anchors + ); +} + +/** + * Remove fenced and inline code segments from Markdown content. + */ +function stripCodeBlocks(content) { + return content + .replaceAll(/```[\s\S]*?```/g, '') + .replaceAll(/~~~[\s\S]*?~~~/g, '') + .replaceAll(/`[^`\n]+`/g, ''); +} + +/** + * Parse link to extract path and anchor. + */ +function parseLink(link) { + const hashIndex = link.indexOf('#'); + if (hashIndex === -1) { + return { path: link, anchor: null }; + } + return { + path: link.slice(0, hashIndex) || null, + anchor: link.slice(hashIndex + 1), + }; +} + +/** + * Get line number for a character position in content. + */ +function getLineNumber(content, charIndex) { + const lines = content.slice(0, charIndex).split('\n'); + return lines.length; +} + +/** + * Extract links with their line numbers from markdown content. + */ +function extractLinksWithPositions(content, filePath) { + const strippedContent = stripCodeBlocks(content); + const links = []; + + let match; + LINK_PATTERN.lastIndex = 0; + + while ((match = LINK_PATTERN.exec(strippedContent)) !== null) { + const rawLink = match[2]; + if (!shouldIgnoreLink(rawLink)) { + const lineNumber = getLineNumber(strippedContent, match.index); + links.push({ + raw: rawLink, + text: match[1], + line: lineNumber, + fullMatch: match[0], + }); + } + } + + return links; +} + +/** + * Resolve a relative link path to an absolute file path. + */ +function resolveLink(fromFile, linkPath) { + if (!linkPath) return fromFile; + + const fromDir = dirname(fromFile); + let resolved = normalize(resolve(fromDir, linkPath)); + + // If link doesn't have extension, try .md + if (!resolved.endsWith('.md') && !resolved.endsWith('.mdx') && !existsSync(resolved)) { + const withMd = resolved + '.md'; + if (existsSync(withMd)) { + return withMd; + } + // Try as directory with index.md + const asIndex = join(resolved, 'index.md'); + if (existsSync(asIndex)) { + return asIndex; + } + } + + return resolved; +} + +/** + * Search for a file that may have moved. + * Uses multiple strategies to find the best match. + * + * @param {string} brokenPath - The original broken link path (e.g., "../tutorials/getting-started/foo.md") + * @returns {string[]} Array of matching absolute paths + */ +async function findMovedFile(brokenPath) { + const fileName = basename(brokenPath); + const searchName = fileName.endsWith('.md') ? fileName : `${fileName}.md`; + + // Strategy 1: Try to match with directory context + // e.g., for "tutorials/getting-started/foo.md", look for "*/getting-started/foo.md" + const pathParts = brokenPath.replace(/^\.\.?\/?/, '').split('/'); + if (pathParts.length >= 2) { + const parentDir = pathParts.at(-2); + const contextPattern = `**/${parentDir}/${searchName}`; + const contextMatches = await glob(contextPattern, { + cwd: DOCS_DIR, + absolute: true, + ignore: ['**/_*/**'], + }); + if (contextMatches.length > 0) { + return contextMatches; + } + } + + // Strategy 2: For non-index files, try filename-only match + // Skip this for index.md since it's too generic (exists in every directory) + if (searchName !== 'index.md') { + const matches = await glob(`**/${searchName}`, { + cwd: DOCS_DIR, + absolute: true, + ignore: ['**/_*/**'], + }); + return matches; + } + + // For index.md with no context match, return empty (truly missing) + return []; +} + +/** + * Calculate the relative path from source file to target file. + */ +function calculateRelativePath(fromFile, toFile) { + const fromDir = dirname(fromFile); + let relativePath = relative(fromDir, toFile); + + // Ensure path starts with ./ or ../ + if (!relativePath.startsWith('.')) { + relativePath = './' + relativePath; + } + + return relativePath; +} + +/** + * Main audit function. + */ +async function main() { + console.log('\n Documentation Link Auditor'); + console.log(' ==========================\n'); + console.log(' Scanning for broken links and attempting auto-resolution...\n'); + + // Find all markdown files, excluding underscore directories + const files = await glob('**/*.{md,mdx}', { + cwd: DOCS_DIR, + absolute: true, + ignore: ['**/_*/**'], + }); + + console.log(` Found ${files.length} markdown files to scan.\n`); + + const brokenLinks = []; + const autoFixable = []; + const needsReview = []; + const missing = []; + + // Track all files for fast lookup + const allFiles = new Set(files); + + for (const file of files) { + const content = readFileSync(file, 'utf-8'); + const links = extractLinksWithPositions(content, file); + const relativePath = relative(DOCS_DIR, file); + + for (const linkInfo of links) { + const { path: linkPath } = parseLink(linkInfo.raw); + + if (!linkPath) continue; // Same-file anchor only + + const targetFile = resolveLink(file, linkPath); + + // Check if target exists + if (!existsSync(targetFile)) { + const fileName = basename(linkPath); + + // Try to find the file elsewhere + const candidates = await findMovedFile(linkPath); + + const brokenInfo = { + sourceFile: relativePath, + sourceFileAbsolute: file, + line: linkInfo.line, + linkText: linkInfo.text, + originalLink: linkInfo.raw, + expectedTarget: linkPath, + fullMatch: linkInfo.fullMatch, + }; + + if (candidates.length === 1) { + // Found exactly one match - auto-fixable + const newPath = calculateRelativePath(file, candidates[0]); + brokenInfo.suggestedFix = newPath; + brokenInfo.foundAt = relative(DOCS_DIR, candidates[0]); + brokenInfo.status = 'auto-fixable'; + autoFixable.push(brokenInfo); + } else if (candidates.length > 1) { + // Multiple matches - needs manual review + brokenInfo.candidates = candidates.map((c) => relative(DOCS_DIR, c)); + brokenInfo.status = 'needs-review'; + needsReview.push(brokenInfo); + } else { + // No matches found + brokenInfo.status = 'missing'; + missing.push(brokenInfo); + } + + brokenLinks.push(brokenInfo); + } + } + } + + // Generate report + const report = { + timestamp: new Date().toISOString(), + summary: { + totalFiles: files.length, + totalBroken: brokenLinks.length, + autoFixable: autoFixable.length, + needsReview: needsReview.length, + missing: missing.length, + }, + autoFixable, + needsReview, + missing, + }; + + // Write JSON report + writeFileSync(REPORT_PATH, JSON.stringify(report, null, 2)); + + // Console output + console.log(' ' + 'β'.repeat(50)); + console.log('\n SUMMARY\n'); + + if (brokenLinks.length === 0) { + console.log(` ${colors.green}β${colors.reset} No broken links found!\n`); + process.exit(0); + } + + console.log(` Total broken links: ${colors.red}${brokenLinks.length}${colors.reset}`); + console.log(` ββ Auto-fixable: ${colors.green}${autoFixable.length}${colors.reset}`); + console.log(` ββ Needs review: ${colors.yellow}${needsReview.length}${colors.reset}`); + console.log(` ββ Missing: ${colors.red}${missing.length}${colors.reset}\n`); + + // Show auto-fixable + if (autoFixable.length > 0) { + console.log(` ${colors.green}AUTO-FIXABLE${colors.reset} (file found elsewhere)\n`); + for (const item of autoFixable) { + console.log(` ${colors.cyan}${item.sourceFile}${colors.reset}:${item.line}`); + console.log(` ${colors.dim}Link:${colors.reset} ${item.originalLink}`); + console.log(` ${colors.dim}Fix:${colors.reset} ${item.suggestedFix}`); + console.log(` ${colors.dim}Found at:${colors.reset} ${item.foundAt}\n`); + } + } + + // Show needs review + if (needsReview.length > 0) { + console.log(` ${colors.yellow}NEEDS REVIEW${colors.reset} (multiple matches found)\n`); + for (const item of needsReview) { + console.log(` ${colors.cyan}${item.sourceFile}${colors.reset}:${item.line}`); + console.log(` ${colors.dim}Link:${colors.reset} ${item.originalLink}`); + console.log(` ${colors.dim}Candidates:${colors.reset}`); + for (const candidate of item.candidates) { + console.log(` - ${candidate}`); + } + console.log(); + } + } + + // Show missing + if (missing.length > 0) { + console.log(` ${colors.red}MISSING${colors.reset} (file not found anywhere)\n`); + for (const item of missing) { + console.log(` ${colors.cyan}${item.sourceFile}${colors.reset}:${item.line}`); + console.log(` ${colors.dim}Link:${colors.reset} ${item.originalLink}\n`); + } + } + + console.log(' ' + 'β'.repeat(50)); + console.log(`\n Report saved to: ${colors.dim}${relative(process.cwd(), REPORT_PATH)}${colors.reset}`); + console.log(`\n To fix auto-fixable links, run:`); + console.log(` node tools/fix-doc-links.js --apply\n`); + + process.exit(1); +} + +main().catch((error) => { + console.error('Error:', error.message); + process.exit(1); +}); diff --git a/tools/fix-doc-links.js b/tools/fix-doc-links.js new file mode 100644 index 00000000..2d700615 --- /dev/null +++ b/tools/fix-doc-links.js @@ -0,0 +1,172 @@ +/** + * Documentation Link Fixer + * + * Reads the audit report generated by audit-doc-links.js and applies fixes + * to broken links where a single match was found. + * + * Usage: + * node tools/fix-doc-links.js # Dry-run (preview changes) + * node tools/fix-doc-links.js --apply # Apply changes + */ + +const { readFileSync, writeFileSync, existsSync } = require('node:fs'); +const { resolve, relative } = require('node:path'); + +const REPORT_PATH = resolve(__dirname, '.link-audit-report.json'); + +// Colors for console output +const colors = { + reset: '\u001B[0m', + red: '\u001B[31m', + green: '\u001B[32m', + yellow: '\u001B[33m', + cyan: '\u001B[36m', + dim: '\u001B[2m', +}; + +/** + * Load the audit report. + */ +function loadReport() { + if (!existsSync(REPORT_PATH)) { + console.error(`\n ${colors.red}Error:${colors.reset} No audit report found.`); + console.error(` Run 'node tools/audit-doc-links.js' first.\n`); + process.exit(1); + } + + try { + const content = readFileSync(REPORT_PATH, 'utf-8'); + return JSON.parse(content); + } catch (error) { + console.error(`\n ${colors.red}Error:${colors.reset} Failed to parse audit report.`); + console.error(` ${error.message}\n`); + process.exit(1); + } +} + +/** + * Apply a fix to a file by replacing the original link with the suggested fix. + */ +function applyFix(filePath, originalLink, suggestedFix) { + const content = readFileSync(filePath, 'utf-8'); + + // Create the replacement pattern - we need to match the exact link in markdown syntax + // Original might have anchor, so we need to handle that + const originalWithoutAnchor = originalLink.split('#')[0]; + const suggestedWithoutAnchor = suggestedFix.split('#')[0]; + + // Also preserve any anchor from the original if the fix doesn't include one + let finalFix = suggestedFix; + if (originalLink.includes('#') && !suggestedFix.includes('#')) { + const anchor = originalLink.slice(originalLink.indexOf('#')); + finalFix = suggestedFix + anchor; + } + + // Replace the link - be careful to only replace inside markdown link syntax + const linkPattern = new RegExp(`\\]\\(${escapeRegex(originalLink)}\\)`, 'g'); + + const newContent = content.replace(linkPattern, `](${finalFix})`); + + if (newContent === content) { + return false; // No change made + } + + writeFileSync(filePath, newContent); + return true; +} + +/** + * Escape special regex characters in a string. + */ +function escapeRegex(string) { + return string.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`); +} + +/** + * Main function. + */ +async function main() { + const args = process.argv.slice(2); + const applyChanges = args.includes('--apply'); + + console.log('\n Documentation Link Fixer'); + console.log(' ========================\n'); + + if (applyChanges) { + console.log(` ${colors.green}APPLYING CHANGES${colors.reset}\n`); + } else { + console.log(` ${colors.yellow}DRY RUN${colors.reset} - No files will be modified.`); + console.log(` Use --apply to apply changes.\n`); + } + + const report = loadReport(); + + if (report.autoFixable.length === 0) { + console.log(` ${colors.green}β${colors.reset} No auto-fixable links found.\n`); + process.exit(0); + } + + console.log(` Found ${report.autoFixable.length} auto-fixable link(s).\n`); + + const fixed = []; + const failed = []; + + // Group fixes by file for efficiency + const byFile = {}; + for (const item of report.autoFixable) { + if (!byFile[item.sourceFileAbsolute]) { + byFile[item.sourceFileAbsolute] = []; + } + byFile[item.sourceFileAbsolute].push(item); + } + + for (const [filePath, items] of Object.entries(byFile)) { + const displayPath = relative(process.cwd(), filePath); + console.log(` ${colors.cyan}${displayPath}${colors.reset}`); + + for (const item of items) { + console.log(` Line ${item.line}:`); + console.log(` ${colors.dim}Old:${colors.reset} ${item.originalLink}`); + console.log(` ${colors.dim}New:${colors.reset} ${item.suggestedFix}`); + + if (applyChanges) { + try { + const success = applyFix(filePath, item.originalLink, item.suggestedFix); + if (success) { + console.log(` ${colors.green}β Fixed${colors.reset}`); + fixed.push(item); + } else { + console.log(` ${colors.yellow}β No match found (may have been fixed already)${colors.reset}`); + } + } catch (error) { + console.log(` ${colors.red}β Error: ${error.message}${colors.reset}`); + failed.push({ ...item, error: error.message }); + } + } + console.log(); + } + } + + // Summary + console.log(' ' + 'β'.repeat(50)); + console.log('\n SUMMARY\n'); + + if (applyChanges) { + console.log(` Fixed: ${colors.green}${fixed.length}${colors.reset}`); + if (failed.length > 0) { + console.log(` Failed: ${colors.red}${failed.length}${colors.reset}`); + } + console.log(`\n Run 'node tools/audit-doc-links.js' to verify remaining issues.\n`); + } else { + console.log(` Would fix: ${colors.yellow}${report.autoFixable.length}${colors.reset} link(s)`); + console.log(`\n To apply these fixes, run:`); + console.log(` node tools/fix-doc-links.js --apply\n`); + } + + process.exit(failed.length > 0 ? 1 : 0); +} + +main().catch((error) => { + console.error('Error:', error.message); + process.exit(1); +});