Files
claude-code/scripts/dump-docs-outline.mjs
claude-code-best 37dac682b9 docs: 文档大重组,对齐 README 入口
以 README 为单一事实来源,重构整个 docs/ 目录。

最终结构(3 大组、15 篇文档):
- 开始: installation / quickstart / model-providers
- 核心功能: pipes-and-lan、acp、channels、chrome-control、computer-use、
  voice-mode、web-browser-tool、auto-dream、remote-control-self-hosting、
  langfuse-monitoring
- 内部机制: growthbook-adapter、sentry-setup

主要变更:
- 删除 56 个 README 未提及的文档(architecture 全部 / guides 全部 /
  features 中未在 README 出现的 20 篇 / internals 中的 5 篇)
- 合并 6 组重复文档(pipes-and-lan、chrome-control、acp、computer-use、
  auto-dream、coordinator-mode 简化为入口)
- features 子组从 5 → 4,ui/ 合并入 tools/
- 所有保留文档加上人性化 frontmatter(title/description/keywords)
- docs.json navigation 简化为 3 大组,redirects 重新过滤为 7 条合并跳转
- 新增 docs.md 工作大纲与验证脚本(verify-docs / check-docs-orphans /
  dump-docs-outline)

总计 130 文件改动,从约 35000 行精简到约 2000 行。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
2026-06-15 16:51:29 +08:00

93 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* 扫描所有 docs/ 文档的 frontmatter按 docs.json 的导航结构输出完整大纲。
* 输出到 stdout可重定向到文件。
*/
import { readFileSync } from 'node:fs'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const ROOT = resolve(__dirname, '..')
const docsJson = JSON.parse(readFileSync(resolve(ROOT, 'docs.json'), 'utf8'))
const EXTS = ['.mdx', '.md']
const readFrontmatter = relPath => {
for (const ext of EXTS) {
try {
const full = resolve(ROOT, relPath + ext)
const text = readFileSync(full, 'utf8')
// 1) 优先 YAML frontmatter
const m = text.match(/^---\n([\s\S]*?)\n---/)
let title = ''
let description = ''
if (m) {
const fm = m[1]
const titleM = fm.match(/^title:\s*"?(.+?)"?\s*$/m)
const descM = fm.match(/^description:\s*"?(.+?)"?\s*$/m)
title = titleM ? titleM[1] : ''
description = descM ? descM[1] : ''
}
// 2) fallback: 第一个 H1 标题
if (!title) {
const h1M = text.match(/^#\s+(.+?)\s*$/m)
if (h1M) title = h1M[1].replace(/\s*[—–-].*$/, '').trim()
}
// 3) fallback: 第一个段落 / 引用作为描述
if (!description) {
const bodyM = text.match(/(?:^|\n)(?:>\s*(.+?)|([^>\n#][^\n]+))\n/)
if (bodyM)
description = (bodyM[1] || bodyM[2] || '').replace(/^>\s*/, '').trim()
}
return { title: title || '(无标题)', description }
} catch {}
}
return null
}
let lines = []
let groupIdx = 0
const emitPage = (pageRef, depth) => {
const fm = readFrontmatter(pageRef)
const indent = ' '.repeat(depth)
if (!fm) {
lines.push(`${indent}- ❓ _MISSING: ${pageRef}_`)
return
}
const short = pageRef.replace(/^docs\//, '')
const desc = fm.description ? `${fm.description}` : ''
lines.push(`${indent}- \`${short}\` — **${fm.title || '(无标题)'}**${desc}`)
}
const emitGroup = (pages, depth) => {
for (const p of pages) {
if (typeof p === 'string') {
emitPage(p, depth)
} else if (p && p.group) {
const indent = ' '.repeat(depth)
lines.push(`${indent}- ### ${p.group}`)
if (p.pages) emitGroup(p.pages, depth + 1)
}
}
}
lines.push('# Claude Code Best 文档大纲')
lines.push('')
lines.push(
`> 自动生成自 docs.json 与各文档 frontmatter。共 ${docsJson.navigation.groups.length} 个顶级分组。`,
)
lines.push('')
for (const g of docsJson.navigation.groups) {
groupIdx++
lines.push(`## ${groupIdx}. ${g.group}`)
lines.push('')
emitGroup(g.pages, 0)
lines.push('')
}
console.log(lines.join('\n'))