From a631e637370e0223ea51faaecf0dd1e4b382ae21 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 23 Jan 2026 08:19:18 +0100 Subject: [PATCH 1/3] site: remove front matter from generated md output The front matter addition an experiment, but I think we should remove it for now. There's no clear reason to include it. Maybe if some sort of standard emerges for structuring front matter for agents, we could consider reintroducing it. But for now I'd remove it to keep things clean and simple. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- layouts/_default/api.markdown.md | 37 ++--------------------------- layouts/_default/cli.markdown.md | 34 +------------------------- layouts/_default/list.markdown.md | 35 +-------------------------- layouts/_default/single.markdown.md | 34 +------------------------- 4 files changed, 5 insertions(+), 135 deletions(-) diff --git a/layouts/_default/api.markdown.md b/layouts/_default/api.markdown.md index ff3bef0693..012b44430c 100644 --- a/layouts/_default/api.markdown.md +++ b/layouts/_default/api.markdown.md @@ -1,38 +1,5 @@ ---- -title: {{ .Title }} -url: {{ .Permalink }} -{{- range .Ancestors }} - {{- if and (not .IsHome) .Permalink }} -parent: - title: {{ .Title }} - url: {{ .Permalink }} - {{- break }} - {{- end }} -{{- end }} -{{- if .Ancestors }} -breadcrumbs: -{{- range .Ancestors.Reverse }} - {{- if and (not .IsHome) .Permalink }} - - title: {{ .Title }} - url: {{ .Permalink }} - {{- end }} -{{- end }} - - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- with .NextInSection }} -next: - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- with .PrevInSection }} -prev: - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- $specURL := urls.Parse (printf "/%s%s.yaml" .File.Dir .File.ContentBaseName) }} -openapi_spec: {{ $specURL.String | absURL }} ---- +{{- $specURL := urls.Parse (printf "/%s%s.yaml" .File.Dir .File.ContentBaseName) -}} +# {{ .Title }} {{ .Content }} diff --git a/layouts/_default/cli.markdown.md b/layouts/_default/cli.markdown.md index 99cfd9ecc0..7c03cb1f0b 100644 --- a/layouts/_default/cli.markdown.md +++ b/layouts/_default/cli.markdown.md @@ -4,39 +4,7 @@ {{- else }} {{- $data = index site.Data .Params.datafile }} {{- end -}} ---- -title: {{ .Title }} -url: {{ .Permalink }} -{{- range .Ancestors }} - {{- if and (not .IsHome) .Permalink }} -parent: - title: {{ .Title }} - url: {{ .Permalink }} - {{- break }} - {{- end }} -{{- end }} -{{- if .Ancestors }} -breadcrumbs: -{{- range .Ancestors.Reverse }} - {{- if and (not .IsHome) .Permalink }} - - title: {{ .Title }} - url: {{ .Permalink }} - {{- end }} -{{- end }} - - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- with .NextInSection }} -next: - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- with .PrevInSection }} -prev: - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} ---- +# {{ .Title }} {{ with $data.short }}**Description:** {{ . }}{{ end }} diff --git a/layouts/_default/list.markdown.md b/layouts/_default/list.markdown.md index ab2747bc38..54f3071376 100644 --- a/layouts/_default/list.markdown.md +++ b/layouts/_default/list.markdown.md @@ -1,36 +1,3 @@ ---- -title: {{ .Title }} -url: {{ .Permalink }} -{{- range .Ancestors }} - {{- if and (not .IsHome) .Permalink }} -parent: - title: {{ .Title }} - url: {{ .Permalink }} - {{- break }} - {{- end }} -{{- end }} -{{- if .Ancestors }} -breadcrumbs: -{{- range .Ancestors.Reverse }} - {{- if and (not .IsHome) .Permalink }} - - title: {{ .Title }} - url: {{ .Permalink }} - {{- end }} -{{- end }} - - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- $children := where .Pages "Permalink" "ne" "" }} -{{- if $children }} -children: -{{- range $children }} - - title: {{ .Title }} - url: {{ .Permalink }} - {{- with .Description }} - description: {{ . }} - {{- end }} -{{- end }} -{{- end }} ---- +# {{ .Title }} {{ .RenderShortcodes }} diff --git a/layouts/_default/single.markdown.md b/layouts/_default/single.markdown.md index 40c1778180..54f3071376 100644 --- a/layouts/_default/single.markdown.md +++ b/layouts/_default/single.markdown.md @@ -1,35 +1,3 @@ ---- -title: {{ .Title }} -url: {{ .Permalink }} -{{- range .Ancestors }} - {{- if and (not .IsHome) .Permalink }} -parent: - title: {{ .Title }} - url: {{ .Permalink }} - {{- break }} - {{- end }} -{{- end }} -{{- if .Ancestors }} -breadcrumbs: -{{- range .Ancestors.Reverse }} - {{- if and (not .IsHome) .Permalink }} - - title: {{ .Title }} - url: {{ .Permalink }} - {{- end }} -{{- end }} - - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- with .NextInSection }} -next: - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} -{{- with .PrevInSection }} -prev: - title: {{ .Title }} - url: {{ .Permalink }} -{{- end }} ---- +# {{ .Title }} {{ .RenderShortcodes }} From bd9a74141c2b5e078321c16f86a73ef754ae8061 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:37:21 +0100 Subject: [PATCH 2/3] site: add markdown output for samples pages Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- layouts/samples/single.markdown.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 layouts/samples/single.markdown.md diff --git a/layouts/samples/single.markdown.md b/layouts/samples/single.markdown.md new file mode 100644 index 0000000000..800197369f --- /dev/null +++ b/layouts/samples/single.markdown.md @@ -0,0 +1,9 @@ +# {{ .Title }} + +| Name | Description | +|------|-------------| +{{- range site.Data.samples.samples }} +{{- if in .services $.Params.service }} +| [{{ .title }}]({{ .url }}) | {{ chomp .description }} | +{{- end }} +{{- end }} From d0128a8c8243a5e65ad7b2002a7a8b9fed479263 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:43:37 +0100 Subject: [PATCH 3/3] hack: resolve links in the markdown output Resolves internal links to point to the corresponding (rendered) path rather than keeping them as internal links, which wouldn't make sense to an agent/llm reading them. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- Dockerfile | 2 +- hack/flatten-and-resolve.js | 236 ++++++++++++++++++++++++++++++++++++ hack/flatten-markdown.sh | 22 ---- netlify.toml | 2 +- 4 files changed, 238 insertions(+), 24 deletions(-) create mode 100755 hack/flatten-and-resolve.js delete mode 100755 hack/flatten-markdown.sh diff --git a/Dockerfile b/Dockerfile index 2ec633711f..51a36ac3fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,7 +51,7 @@ ARG DOCS_URL="https://docs.docker.com" ENV HUGO_CACHEDIR="/tmp/hugo_cache" RUN --mount=type=cache,target=/tmp/hugo_cache \ hugo --gc --minify -e $HUGO_ENV -b $DOCS_URL -RUN ./hack/flatten-markdown.sh public +RUN ./hack/flatten-and-resolve.js public # lint lints markdown files FROM ghcr.io/igorshubovych/markdownlint-cli:v0.45.0 AS lint diff --git a/hack/flatten-and-resolve.js b/hack/flatten-and-resolve.js new file mode 100755 index 0000000000..04532d343e --- /dev/null +++ b/hack/flatten-and-resolve.js @@ -0,0 +1,236 @@ +#!/usr/bin/env node + +/** + * Flattens markdown directory structure and resolves all links to absolute paths. + * + * This script: + * 1. Moves index.md files up one level (ai/model-runner/index.md -> ai/model-runner.md) + * 2. Fixes _index.md and index.md references in links + * 3. Strips /manuals/ prefix from paths (Hugo config removes this) + * 4. Resolves all relative links to absolute HTML paths for RAG ingestion + * + * Usage: node flatten-and-resolve.js [public-dir] + */ + +const fs = require('fs'); +const path = require('path'); + +const PUBLIC_DIR = path.resolve(process.argv[2] || 'public'); + +if (!fs.existsSync(PUBLIC_DIR)) { + console.error(`Error: Directory ${PUBLIC_DIR} does not exist`); + process.exit(1); +} + +/** + * Recursively find all files matching a predicate + */ +function findFiles(dir, predicate) { + const results = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + results.push(...findFiles(fullPath, predicate)); + } else if (entry.isFile() && predicate(entry.name)) { + results.push(fullPath); + } + } + + return results; +} + +/** + * Step 1: Flatten index.md files + * Move path/to/section/index.md -> path/to/section.md + * Before moving, rewrite sibling links (e.g., "get-started.md" -> "section/get-started.md") + */ +function flattenIndexFiles() { + const indexFiles = findFiles(PUBLIC_DIR, name => name === 'index.md'); + let count = 0; + + for (const file of indexFiles) { + // Skip root index.md + if (file === path.join(PUBLIC_DIR, 'index.md')) { + continue; + } + + const dir = path.dirname(file); + const dirname = path.basename(dir); + + // Read content and fix sibling links + let content = fs.readFileSync(file, 'utf8'); + + // Rewrite relative links that don't start with /, ../, or http + // These are sibling files that will become children after flattening + content = content.replace( + /\[([^\]]+)\]\(([a-zA-Z0-9][^):]*)\)/g, + (match, text, link) => { + // Skip if it's a URL or starts with special chars + if (link.startsWith('http://') || link.startsWith('https://') || + link.startsWith('#')) { + return match; + } + return `[${text}](${dirname}/${link})`; + } + ); + + // Also fix reference-style links + content = content.replace( + /^\[([^\]]+)\]:\s+([a-zA-Z0-9][^: ]*\.md)$/gm, + (match, ref, link) => `[${ref}]: ${dirname}/${link}` + ); + + fs.writeFileSync(file, content, 'utf8'); + + // Move file up one level + const parentDir = path.dirname(dir); + const newPath = path.join(parentDir, `${dirname}.md`); + fs.renameSync(file, newPath); + + count++; + } + + console.log(`Flattened ${count} index.md files`); + return count; +} + +/** + * Step 2: Fix _index.md and index.md references in all files + * Also strip /manuals/ prefix from paths + */ +function fixIndexReferences() { + const mdFiles = findFiles(PUBLIC_DIR, name => name.endsWith('.md')); + let count = 0; + + for (const file of mdFiles) { + const dir = path.dirname(file); + const dirname = path.basename(dir); + const parentDir = path.dirname(dir); + const parentDirname = path.basename(parentDir); + + let content = fs.readFileSync(file, 'utf8'); + const original = content; + + // Fix path/_index.md or path/index.md -> path.md + content = content.replace(/([a-zA-Z0-9_/-]+)\/_?index\.md/g, '$1.md'); + + // Fix bare _index.md or index.md -> ../dirname.md + content = content.replace(/_?index\.md/g, `../${dirname}.md`); + + // Fix ../_index.md that became ...md -> ../../parentdirname.md + if (parentDir !== PUBLIC_DIR) { + content = content.replace(/\.\.\.md/g, `../../${parentDirname}.md`); + } + + // Strip /manuals/ prefix (both /manuals/ and manuals/) + content = content.replace(/\/?manuals\//g, '/'); + + if (content !== original) { + fs.writeFileSync(file, content, 'utf8'); + count++; + } + } + + console.log(`Fixed _index.md references in ${count} files`); + return count; +} + +/** + * Step 3: Resolve all relative links to absolute HTML paths + */ +function resolveLinks() { + const mdFiles = findFiles(PUBLIC_DIR, name => name.endsWith('.md')); + let count = 0; + + for (const file of mdFiles) { + let content = fs.readFileSync(file, 'utf8'); + const original = content; + + // Process inline links: [text](path) + content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, link) => { + const resolved = resolveLinkPath(link, file); + return `[${text}](${resolved})`; + }); + + // Process reference-style links: [ref]: path + content = content.replace(/^\[([^\]]+)\]:\s+(.+)$/gm, (match, ref, link) => { + const resolved = resolveLinkPath(link, file); + return `[${ref}]: ${resolved}`; + }); + + if (content !== original) { + fs.writeFileSync(file, content, 'utf8'); + count++; + } + } + + console.log(`Resolved links in ${count} files`); + return count; +} + +/** + * Resolve a link path to absolute HTML format + */ +function resolveLinkPath(linkPath, currentFile) { + // Skip external URLs and mailto + if (linkPath.startsWith('http://') || linkPath.startsWith('https://') || + linkPath.startsWith('mailto:')) { + return linkPath; + } + + // Skip same-page anchors + if (linkPath.startsWith('#')) { + return linkPath; + } + + // Split path and anchor + const hashIndex = linkPath.indexOf('#'); + const pathPart = hashIndex >= 0 ? linkPath.substring(0, hashIndex) : linkPath; + const anchorPart = hashIndex >= 0 ? linkPath.substring(hashIndex) : ''; + + if (!pathPart) { + // Just an anchor + return linkPath; + } + + // Handle absolute paths - just convert to HTML format + if (pathPart.startsWith('/')) { + return toHtmlPath(pathPart) + anchorPart; + } + + // Resolve relative path to absolute + const currentDir = path.dirname(currentFile); + const absolutePath = path.resolve(currentDir, pathPart); + const relativePath = path.relative(PUBLIC_DIR, absolutePath); + + // Convert to URL path (forward slashes) + const urlPath = '/' + relativePath.split(path.sep).join('/'); + + return toHtmlPath(urlPath) + anchorPart; +} + +/** + * Convert a path to HTML format (strip .md, add trailing /) + */ +function toHtmlPath(urlPath) { + if (urlPath.endsWith('.md')) { + return urlPath.slice(0, -3) + '/'; + } + return urlPath; +} + +// Main execution +console.log('Starting markdown flattening and link resolution...'); +console.log(''); + +const flattenCount = flattenIndexFiles(); +const fixCount = fixIndexReferences(); +const resolveCount = resolveLinks(); + +console.log(''); +console.log('Done!'); +console.log(`- Flattened: ${flattenCount} files`); +console.log(`- Fixed references: ${fixCount} files`); +console.log(`- Resolved links: ${resolveCount} files`); diff --git a/hack/flatten-markdown.sh b/hack/flatten-markdown.sh deleted file mode 100755 index d055dc9bdb..0000000000 --- a/hack/flatten-markdown.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -set -e - -# Flatten markdown files from public/path/to/page/index.md to public/path/to/page.md -# This makes markdown output links work correctly - -PUBLIC_DIR="${1:-public}" - -[ -d "$PUBLIC_DIR" ] || { echo "Error: Directory $PUBLIC_DIR does not exist"; exit 1; } - -find "$PUBLIC_DIR" -type f -name 'index.md' | while read -r file; do - # Skip the root index.md - [ "$file" = "$PUBLIC_DIR/index.md" ] && continue - - # Get the directory containing index.md - dir="${file%/*}" - - # Move index.md to parent directory with directory name - mv "$file" "${dir%/*}/${dir##*/}.md" -done - -echo "Flattened markdown files in $PUBLIC_DIR" diff --git a/netlify.toml b/netlify.toml index 6cee9928c0..cb07b6343c 100644 --- a/netlify.toml +++ b/netlify.toml @@ -10,4 +10,4 @@ HUGO_ENVIRONMENT = "preview" SECRETS_SCAN_OMIT_PATHS = "public/contribute/file-conventions/index.html" [context.deploy-preview] -command = "hugo --gc --minify -b $DEPLOY_PRIME_URL && ./hack/flatten-markdown.sh && npx pagefind@v1.3.0" +command = "hugo --gc --minify -b $DEPLOY_PRIME_URL && ./hack/flatten-and-resolve.js && npx pagefind@v1.3.0"