From 6b7a0807e73502dc6a4b350384dfed469faa9527 Mon Sep 17 00:00:00 2001 From: Karsten Date: Sat, 25 Jul 2026 22:53:49 +0200 Subject: [PATCH] Fix doc updater: docs moved to code.claude.com The docs relocated off docs.claude.com, which broke update_docs.js in three ways: - fetchUrl treated any non-2xx as fatal, so the 301 on llms.txt killed the script immediately. Now follows up to 5 redirects. - docs.claude.com/llms.txt redirects to platform.claude.com/llms.txt, the API docs index, which lists no Claude Code pages. The Claude Code index is code.claude.com/llms.txt, and the path shape changed from /en/docs/claude-code/.md to /docs/en/.md. - 48 of the 172 new pages are nested and 8 basenames collide (hooks, mcp, overview, permissions, plugins, quickstart, sessions, skills), so path.basename() silently overwrote real docs. Nested paths now flatten, e.g. agent-sdk/hooks.md -> agent-sdk-hooks.md. Fixes #7 Co-Authored-By: Claude Opus 5 (1M context) --- .../scripts/update_docs.js | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/skills/working-with-claude-code/scripts/update_docs.js b/skills/working-with-claude-code/scripts/update_docs.js index 1ed8627..17b017c 100755 --- a/skills/working-with-claude-code/scripts/update_docs.js +++ b/skills/working-with-claude-code/scripts/update_docs.js @@ -13,23 +13,38 @@ const https = require('https'); const fs = require('fs'); const path = require('path'); -const LLMS_TXT_URL = 'https://docs.claude.com/llms.txt'; -const CLAUDE_CODE_PATTERN = /https:\/\/docs\.claude\.com\/en\/docs\/claude-code\/[^\s)]+\.md/g; +const LLMS_TXT_URL = 'https://code.claude.com/llms.txt'; +const CLAUDE_CODE_PATTERN = /https:\/\/code\.claude\.com\/docs\/en\/[^\s)]+\.md/g; +const DOC_PATH_PREFIX = '/docs/en/'; const REFERENCES_DIR = path.join(__dirname, '..', 'references'); /** * Fetch content from a URL using https module */ -function fetchUrl(url) { +function fetchUrl(url, redirectsLeft = 5) { return new Promise((resolve, reject) => { https.get(url, (res) => { + const { statusCode, headers } = res; + + // Follow redirects - docs.claude.com moved to code.claude.com + if (statusCode >= 300 && statusCode < 400 && headers.location) { + res.resume(); + if (redirectsLeft === 0) { + reject(new Error(`Too many redirects for ${url}`)); + return; + } + const next = new URL(headers.location, url).toString(); + resolve(fetchUrl(next, redirectsLeft - 1)); + return; + } + let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { - if (res.statusCode >= 200 && res.statusCode < 300) { + if (statusCode >= 200 && statusCode < 300) { resolve(data); } else { - reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`)); + reject(new Error(`HTTP ${statusCode}: ${res.statusMessage}`)); } }); }).on('error', reject); @@ -57,7 +72,12 @@ async function getClaudeCodeUrls() { * Fetch and save a single documentation page */ async function fetchAndSaveDoc(url) { - const filename = path.basename(url); + // Flatten nested doc paths (agent-sdk/hooks.md -> agent-sdk-hooks.md) so + // sibling sections don't clobber each other's basenames. + const idx = url.indexOf(DOC_PATH_PREFIX); + const filename = idx === -1 + ? path.basename(url) + : url.slice(idx + DOC_PATH_PREFIX.length).replace(/\//g, '-'); const filepath = path.join(REFERENCES_DIR, filename); try {