Skip to content

Commit e82bc93

Browse files
committed
fix(docs): resolve remaining htmltest validation issues
1 parent 958845e commit e82bc93

File tree

6 files changed

+66
-11
lines changed

6 files changed

+66
-11
lines changed

docs/explanation/bmm/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The BMad Method is meant to be adapted and customized to your specific needs. In
2929

3030
First know there is the full BMad Method Process and then there is a Quick Flow for those quicker smaller efforts.
3131

32-
- **[Full Adaptive BMad Method](#workflow-guides)** - Full planning and scope support through extensive development and testing.
32+
- **[Full Adaptive BMad Method](#-workflow-guides)** - Full planning and scope support through extensive development and testing.
3333
- Broken down into 4 phases, all of which are comprised of both required and optional phases
3434
- Phases 1-3 are all about progressive idea development through planning and preparations to build your project.
3535
- Phase 4 is the implementation cycle where you will Just In Time (JIT) produce the contextual stories needed for the dev agent based on the extensive planning completed

docs/how-to/get-answers-about-bmad.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Fetch `llms-full.txt` into your session:
4545
https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt
4646
```
4747

48-
You can also find this and other downloadable resources on the [Downloads page](/downloads).
48+
You can also find this and other downloadable resources on the [Downloads page](/downloads/).
4949

5050
:::tip[Verify Surprising Answers]
5151
LLMs occasionally get things wrong. If an answer seems off, check the source file it referenced or ask on Discord.

docs/tutorials/advanced/create-custom-agent.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ Edit the agent YAML directly or use the customization file in `_bmad/_config/age
148148
Yes. Package your agent as a standalone module and share it with your team or the community.
149149

150150
**Where can I see example agents?**
151-
Study the reference agents in `src/modules/bmb/reference/agents/`:
152-
- [commit-poet](https://github.com/bmad-code-org/BMAD-METHOD/tree/main/src/modules/bmb/reference/agents/simple-examples/commit-poet.agent.yaml) (Simple)
153-
- [journal-keeper](https://github.com/bmad-code-org/BMAD-METHOD/tree/main/src/modules/bmb/reference/agents/expert-examples/journal-keeper) (Expert)
151+
Study the reference agents in `src/modules/bmb/workflows/agent/data/reference/`:
152+
- [commit-poet](https://github.com/bmad-code-org/BMAD-METHOD/tree/main/src/modules/bmb/workflows/agent/data/reference/simple-examples/commit-poet.agent.yaml) (Simple)
153+
- [journal-keeper](https://github.com/bmad-code-org/BMAD-METHOD/tree/main/src/modules/bmb/workflows/agent/data/reference/expert-examples/journal-keeper) (Expert)
154154

155155
## Getting Help
156156

tools/build-docs.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ function runAstroBuild() {
335335
stdio: 'inherit',
336336
env: {
337337
...process.env,
338+
SITE_URL,
338339
NODE_OPTIONS: `${process.env.NODE_OPTIONS || ''} --disable-warning=MODULE_TYPELESS_PACKAGE_JSON`.trim(),
339340
},
340341
});
@@ -359,6 +360,18 @@ function copyArtifactsToSite(artifactsDir, siteDir) {
359360
if (fs.existsSync(downloadsDir)) {
360361
copyDirectory(downloadsDir, path.join(siteDir, 'downloads'));
361362
}
363+
364+
// Create base path symlink for local testing with htmltest
365+
// This allows htmltest to resolve absolute paths like /BMAD-METHOD/...
366+
const url = new URL(SITE_URL);
367+
const basePath = url.pathname.replaceAll(/^\/|\/$/g, ''); // Strip leading/trailing slashes
368+
if (basePath) {
369+
const symlinkPath = path.join(siteDir, basePath);
370+
if (!fs.existsSync(symlinkPath)) {
371+
fs.symlinkSync(siteDir, symlinkPath);
372+
console.log(` → Created base path symlink: ${basePath}/`);
373+
}
374+
}
362375
}
363376

364377
// =============================================================================

tools/check-doc-links.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function headingToAnchor(heading) {
5353
.replaceAll(/[^\w\s-]/g, '') // Remove special chars except hyphens
5454
.replaceAll(/\s+/g, '-') // Spaces to hyphens
5555
.replaceAll(/-+/g, '-') // Collapse multiple hyphens
56-
.replaceAll(/^-+|-+$/g, ''); // Trim leading/trailing hyphens
56+
.replaceAll(/-+$/g, ''); // Trim trailing hyphens only (Starlight keeps leading hyphens from emoji removal)
5757
}
5858

5959
/**

tools/verify-build-links.js

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@
2424
* 1 - Broken links found or build directory missing
2525
*/
2626

27-
const { readFileSync, existsSync, statSync, readdirSync } = require('node:fs');
27+
const { readFileSync, existsSync, statSync, lstatSync, readdirSync } = require('node:fs');
2828
const { resolve, join, dirname, relative, normalize } = require('node:path');
2929

3030
const BUILD_DIR = resolve(process.cwd(), 'build/site');
3131
const DOCS_DIR = resolve(process.cwd(), 'docs');
3232

33+
// Base path to strip from absolute links (auto-detected from HTML)
34+
let BASE_PATH = '';
35+
3336
// ANSI color codes
3437
const colors = {
3538
reset: '\u001B[0m',
@@ -51,9 +54,14 @@ function findHtmlFiles(dir, fileList = []) {
5154

5255
for (const file of files) {
5356
const filePath = join(dir, file);
54-
const stat = statSync(filePath);
57+
const lstat = lstatSync(filePath);
58+
59+
// Skip symlinks to avoid infinite loops
60+
if (lstat.isSymbolicLink()) {
61+
continue;
62+
}
5563

56-
if (stat.isDirectory()) {
64+
if (lstat.isDirectory()) {
5765
findHtmlFiles(filePath, fileList);
5866
} else if (file.endsWith('.html')) {
5967
fileList.push(filePath);
@@ -112,6 +120,26 @@ function isInternalLink(link) {
112120
return true;
113121
}
114122

123+
/**
124+
* Detect base path from the first HTML file's canonical or sitemap link
125+
*/
126+
function detectBasePath(htmlFiles) {
127+
for (const htmlFile of htmlFiles) {
128+
const content = readFileSync(htmlFile, 'utf-8');
129+
// Look for sitemap link which shows the base path
130+
const sitemapMatch = content.match(/href="(\/[^"]*?)sitemap-index\.xml"/);
131+
if (sitemapMatch) {
132+
return sitemapMatch[1].slice(0, -1); // Remove trailing /
133+
}
134+
// Fallback: look for favicon link
135+
const faviconMatch = content.match(/href="(\/[^"]*?)favicon\.ico"/);
136+
if (faviconMatch) {
137+
return faviconMatch[1].slice(0, -1);
138+
}
139+
}
140+
return '';
141+
}
142+
115143
/**
116144
* Resolve a link to an absolute file path in the build directory
117145
*/
@@ -126,7 +154,14 @@ function resolveLinkToPath(fromHtmlPath, link) {
126154

127155
// Handle absolute paths (starting with /)
128156
if (linkWithoutHash.startsWith('/')) {
129-
const cleanPath = linkWithoutHash.slice(1); // Remove leading /
157+
let cleanPath = linkWithoutHash;
158+
// Strip base path if present
159+
if (BASE_PATH && cleanPath.startsWith(BASE_PATH + '/')) {
160+
cleanPath = cleanPath.slice(BASE_PATH.length);
161+
} else if (BASE_PATH && cleanPath === BASE_PATH) {
162+
cleanPath = '/';
163+
}
164+
cleanPath = cleanPath.slice(1); // Remove leading /
130165
return join(BUILD_DIR, cleanPath);
131166
}
132167

@@ -221,7 +256,14 @@ async function verifyBuildLinks() {
221256

222257
// Find all HTML files
223258
const htmlFiles = findHtmlFiles(BUILD_DIR);
224-
console.log(`Found ${htmlFiles.length} HTML files\n`);
259+
console.log(`Found ${htmlFiles.length} HTML files`);
260+
261+
// Detect base path from HTML
262+
BASE_PATH = detectBasePath(htmlFiles);
263+
if (BASE_PATH) {
264+
console.log(`Detected base path: ${BASE_PATH}`);
265+
}
266+
console.log();
225267

226268
// Category tracking
227269
const categories = {

0 commit comments

Comments
 (0)