Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions build-archived-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/bin/bash
set -euo pipefail

# build-archived-version.sh - Build a standalone static Docusaurus site for an archived version
#
# Usage: ./build-archived-version.sh <version-tag> [--llama-stack-dir <path>]
#
# Examples:
# ./build-archived-version.sh v0.5.0
# ./build-archived-version.sh v0.6.0 --llama-stack-dir /tmp/llama-stack
#
# Output: docs/<version-tag>/ containing the full static site

VERSION="${1:?Usage: $0 <version-tag> [--llama-stack-dir <path>]}"
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"

# Parse optional arguments
LLAMA_STACK_DIR=""
shift
while [[ $# -gt 0 ]]; do
case $1 in
--llama-stack-dir) LLAMA_STACK_DIR="$2"; shift 2 ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done

# Setup temp directory for the build
TEMP_DIR=$(mktemp -d)
BUILD_DIR="$TEMP_DIR/llama-stack/docs"
trap 'rm -rf "$TEMP_DIR"' EXIT

echo "=== Building archived version $VERSION ==="

# Step 1: Get llama-stack at the specified version
if [ -n "$LLAMA_STACK_DIR" ] && [ -d "$LLAMA_STACK_DIR" ]; then
echo "--- Cloning from local repo ---"
git clone --local --no-checkout "$LLAMA_STACK_DIR" "$TEMP_DIR/llama-stack"
cd "$TEMP_DIR/llama-stack"
git checkout "$VERSION" 2>/dev/null || git checkout "tags/$VERSION"
else
echo "--- Cloning from GitHub ---"
git clone --depth 1 --branch "$VERSION" https://github.com/llamastack/llama-stack.git "$TEMP_DIR/llama-stack"
fi

cd "$BUILD_DIR"

# Step 2: Install dependencies
echo "--- Installing dependencies ---"
npm ci 2>&1 | tail -5

# Step 3: Generate API docs
echo "--- Generating API docs ---"

if [ -f "static/llama-stack-spec.yaml" ]; then
npm run gen-api-docs stable 2>&1 | grep -E "^Successfully" || true
fi

if [ -f "static/experimental-llama-stack-spec.yaml" ]; then
npm run gen-api-docs experimental 2>&1 | grep -E "^Successfully" || true
fi

if [ -f "static/deprecated-llama-stack-spec.yaml" ]; then
npm run gen-api-docs deprecated 2>&1 | grep -E "^Successfully" || true
fi

# Step 4: Inline raw-loader imports
echo "--- Inlining raw-loader imports ---"
python3 "$REPO_DIR/inline-raw-loader.py" docs "$TEMP_DIR/llama-stack"

# Step 5: Fix MDX compatibility issues
echo "--- Fixing MDX compatibility ---"
python3 "$REPO_DIR/fix-mdx-compat.py" docs

# Step 6: Patch config for standalone archived build
echo "--- Patching config for baseUrl: /$VERSION/ ---"
export VERSION
node << 'CONFIGEOF'
const fs = require('fs');
const version = process.env.VERSION;

let config = fs.readFileSync('docusaurus.config.ts', 'utf8');

// Set baseUrl to /vX.Y.Z/
config = config.replace(
/baseUrl:\s*["'][^"']*["']/,
`baseUrl: '/${version}/'`
);

// Add announcement banner for archived version inside themeConfig
const bannerEntry = `
announcementBar: {
id: 'archived_version',
content: 'This is documentation for <b>${version}</b>. For the latest version, visit <a href="https://llamastack.github.io/">the main site</a>.',
backgroundColor: '#2b3137',
textColor: '#ffffff',
isCloseable: false,
},`;

// Insert after "themeConfig: {"
config = config.replace(
/themeConfig:\s*\{/,
`themeConfig: {${bannerEntry}`
);

// Fix blog include pattern to support both .md and .mdx
config = config.replace(
/include:\s*\['?\*\.md'?\]/g,
"include: ['*.{md,mdx}']"
);

fs.writeFileSync('docusaurus.config.ts', config);
console.log('Config patched');
CONFIGEOF

# Step 7: Build
echo "--- Building ---"
NODE_OPTIONS="--max-old-space-size=8192" npm run build 2>&1 | tail -50

# Step 8: Copy build output to docs/<version>/
echo "--- Copying to docs/$VERSION/ ---"
OUTPUT_DIR="$REPO_DIR/docs/$VERSION"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
cp -r build/* "$OUTPUT_DIR/"

echo "=== Done building $VERSION ==="
echo "Output: docs/$VERSION/"
du -sh "$OUTPUT_DIR"
51 changes: 51 additions & 0 deletions docs/versions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Llama Stack Documentation Versions</title>
<style>
:root { --primary: #7C3AED; --bg: #1a1a2e; --surface: #16213e; --text: #e0e0e0; --muted: #a0a0a0; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; }
.container { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem; }
h1 { font-size: 1.8rem; margin-bottom: 0.5rem; }
.subtitle { color: var(--muted); margin-bottom: 2rem; }
.latest { background: var(--primary); color: white; padding: 1rem 1.5rem; border-radius: 8px; margin-bottom: 2rem; display: flex; justify-content: space-between; align-items: center; }
.latest a { color: white; text-decoration: none; font-weight: 600; font-size: 1.1rem; }
.latest .badge { background: rgba(255,255,255,0.2); padding: 0.2rem 0.6rem; border-radius: 4px; font-size: 0.85rem; }
.version-list { list-style: none; }
.version-list li { border-bottom: 1px solid rgba(255,255,255,0.1); }
.version-list a { display: block; padding: 0.8rem 0; color: var(--text); text-decoration: none; transition: color 0.2s; }
.version-list a:hover { color: var(--primary); }
.version-name { font-weight: 500; }
.back { margin-top: 2rem; }
.back a { color: var(--primary); text-decoration: none; }
.back a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="container">
<h1>Documentation Versions</h1>
<p class="subtitle">All published versions of the Llama Stack documentation.</p>
<div class="latest">
<a href="https://llamastack.github.io/">Latest (main)</a>
<span class="badge">current</span>
</div>
<ul class="version-list" id="versions"></ul>
<p class="back"><a href="https://llamastack.github.io/">Back to latest docs</a></p>
</div>
<script>
fetch('/versionsArchived.json')
.then(function(r) { return r.json(); })
.then(function(versions) {
var list = document.getElementById('versions');
Object.entries(versions).forEach(function(entry) {
var li = document.createElement('li');
li.innerHTML = '<a href="' + entry[1] + '"><span class="version-name">' + entry[0] + '</span></a>';
list.appendChild(li);
});
});
</script>
</body>
</html>
14 changes: 14 additions & 0 deletions docs/versionsArchived.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"v0.2.22": "https://llamastack.github.io/v0.2.22/",
"v0.2.21": "https://llamastack.github.io/v0.2.21/",
"v0.2.20": "https://llamastack.github.io/v0.2.20/",
"v0.2.19": "https://llamastack.github.io/v0.2.19/",
"v0.2.18": "https://llamastack.github.io/v0.2.18/",
"v0.2.17": "https://llamastack.github.io/v0.2.17/",
"v0.2.16": "https://llamastack.github.io/v0.2.16/",
"v0.2.15": "https://llamastack.github.io/v0.2.15/",
"v0.2.14": "https://llamastack.github.io/v0.2.14/",
"v0.2.13": "https://llamastack.github.io/v0.2.13/",
"v0.2.12": "https://llamastack.github.io/v0.2.12/",
"v0.2.11": "https://llamastack.github.io/v0.2.11/"
}
136 changes: 136 additions & 0 deletions fix-mdx-compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""Fix MDX-incompatible syntax in markdown/mdx files.

Usage: python3 fix-mdx-compat.py <docs_dir>

Fixes patterns that break Docusaurus MDX v3 parser:
- <|...|> (LLM special tokens) -> &lt;|...|>
- <<EOF -> &lt;&lt;EOF
- { and } outside code fences/inline code -> \{ and \}

Only processes files that have <| or <<EOF patterns.
Skips files with JSX components (imports, <ComponentName>).
"""

import re
import os
import sys
import glob


def needs_fixing(content):
"""Check if file has patterns that need fixing."""
in_code_fence = False
for line in content.split("\n"):
stripped = line.strip()
if stripped.startswith("```") or stripped.startswith("~~~"):
in_code_fence = not in_code_fence
continue
if in_code_fence:
continue
if "<|" in line or "<<EOF" in line:
return True
return False


def has_jsx_components(content):
"""Check if the file uses JSX components that would break with escaping."""
for line in content.split("\n"):
stripped = line.strip()
if re.match(r"^import\s+", stripped):
return True
if re.search(r"<[A-Z]\w+[\s/>]", stripped):
return True
return False


def fix_line(line):
"""Fix a single line outside code fences."""
# Escape <| and <<
line = line.replace("<|", "&lt;|")
line = re.sub(r"<<(\w+)", r"&lt;&lt;\1", line)

# Escape { and } outside inline code spans
parts = re.split(r"(`[^`]+`)", line)
escaped_parts = []
for part in parts:
if part.startswith("`") and part.endswith("`"):
escaped_parts.append(part)
else:
part = re.sub(r"(?<!\\)(?<!\{)\{(?!\{)", r"\\{", part)
part = re.sub(r"(?<!\\)(?<!\})\}(?!\})", r"\\}", part)
escaped_parts.append(part)
return "".join(escaped_parts)


def fix_mdx_file(filepath):
"""Fix MDX-incompatible syntax in a single file."""
with open(filepath, "r") as f:
content = f.read()

if not needs_fixing(content):
return False

if has_jsx_components(content):
return False

lines = content.split("\n")
result = []
in_code_fence = False
in_frontmatter = False
frontmatter_count = 0

for line in lines:
stripped = line.strip()

# Track frontmatter
if stripped == "---":
frontmatter_count += 1
in_frontmatter = frontmatter_count == 1
result.append(line)
continue
if in_frontmatter:
result.append(line)
continue

# Track code fences
if stripped.startswith("```") or stripped.startswith("~~~"):
in_code_fence = not in_code_fence
result.append(line)
continue

if in_code_fence:
result.append(line)
continue

result.append(fix_line(line))

new_content = "\n".join(result)
if new_content != content:
with open(filepath, "w") as f:
f.write(new_content)
return True
return False


def fix_docs_dir(docs_dir):
"""Fix all markdown/mdx files in a directory."""
if not os.path.isdir(docs_dir):
print(f"No dir: {docs_dir}")
return

fixed = 0
for ext in ("*.md", "*.mdx"):
for filepath in glob.glob(f"{docs_dir}/**/{ext}", recursive=True):
if fix_mdx_file(filepath):
print(f" Fixed: {filepath}")
fixed += 1

print(f"Fixed {fixed} files")


if __name__ == "__main__":
if len(sys.argv) != 2:
print(__doc__)
sys.exit(1)
fix_docs_dir(sys.argv[1])
Loading
Loading