Skill Seekers Man Page 技能生成解析:references/index.md 参考索引的结构、分类机制与统计口径
2026/9/23 21:37:32 网站建设 项目流程

Skill Seekers Man Page 技能生成解析:references/index.md 参考索引的结构、分类机制与统计口径

【免费下载链接】Skill_SeekersConvert documentation websites, GitHub repositories, and PDFs into Claude AI skills with automatic conflict detection项目地址: https://gitcode.com/gh_mirrors/sk/Skill_Seekers

本篇技术指南以 Skill Seekers 开源项目中 man 页面技能生成的黄金参考索引(tests/golden/phase2/man/references/index.md)为核心线索,系统讲解"man 页面 → Claude Skill"转换管线的输出结构、自动分类机制、统计口径以及黄金测试的字节级验证方式。读完本文,你将理解--man-names/--man-path/--sections/--from-json四个 CLI 参数背后的完整工作流,并能读懂任何由该工具生成的技能目录中references/SKILL.md的每个字段。

一、黄金参考索引是什么

tests/golden/phase2/man/references/index.md是 Skill Seekers 项目中 man 页面抓取器(Man Page Scraper)生成的技能目录里的"导航枢纽"。它由转换器在构建阶段自动写出,作用是把某个技能下所有 man 页面按照分类聚合后的引用文件组织起来,形成三类信息:

  1. Categories(分类清单)——列出每个分类及其对应的引用文件,例如[Git](https://link.gitcode.com/i/0bd7801b34e8d2d96ee9a45b4e0fbd64) (2 man page(s))
  2. All Man Pages(全量页面清单)——按名称排序列出每一页的命令名与标题,例如git-diff(1) -- git-diff - Show changes between commits
  3. Statistics(统计口径)——汇总本次转换的总页数、总选项数、总示例数与跨引用数。

该文件之所以放在tests/golden/目录下,是因为它同时也是黄金(golden)测试的基准快照:测试代码会把转换器重新生成的结果与该目录下的文件逐字节比对,以验证重构后的代码与旧实现完全一致。因此,这个文件不仅是一份技能产物,更是一份"生成规则的冻结契约"。

与之配套的还有同目录下的分类引用文件 git_01.md、curl_02.md,以及技能入口文件 SKILL.md。四个文件共同构成一个完整的 man 技能产物。

二、index.md 三大部分逐段解读

以 golden 目录中的 index.md 为例,全文仅四段,但每一段都对应ManPageToSkillConverter._generate_index()的一行生成逻辑。

2.1 Categories:分类与引用文件的映射

## Categories - [Git](https://link.gitcode.com/i/0bd7801b34e8d2d96ee9a45b4e0fbd64) (2 man page(s)) - [Curl](https://link.gitcode.com/i/2d1e2d18ea6060c473fcd44a26bcba3a) (1 man page(s))

这一段的生成逻辑位于 man_scraper.py:遍历categorize_content()产出的分类字典,对每个分类写出- {title} ({count} man page(s))。其中link_filename的命名规则是:

  • 分类总数只有 1 个时,引用文件为无编号的{cat_key}.md(如man_single黄金树中的情形);
  • 分类总数大于 1 时,引用文件为带两位序号的文件名{cat_key}_{cat_num:02d}.mdcat_num从 1 开始递增。

本示例有gitcurl两个分类,因此得到git_01.mdcurl_02.md序号来自分类在字典中的遍历顺序,而非页面的重要性排序。

2.2 All Man Pages:按名称排序的全量清单

## All Man Pages - **curl** -- curl - **git-diff(1)** -- git-diff - Show changes between commits - **git-log(1)** -- git-log - Show commit logs

对应生成代码见 man_scraper.py:把解析出的所有页面按name字段排序后,每行输出- **{name}{section_label}** -- {title}。有两个细节值得注意:

  • section_label只在页面确实携带手册分区号时出现,形如(1);没有分区号的页面(如本示例中的curl)则直接输出裸命令名;
  • 排序用的是 Python 字典序,因此curl排在git-diffgit-log之前。

2.3 Statistics:四类统计数字的来源

## Statistics - Total man pages: 3 - Total options: 3 - Total examples: 3 - Cross-references: 3

生成逻辑见 man_scraper.py,四个数字均来自提取阶段extract_manpages()写入中间 JSON 的汇总字段:

字段含义计算方式
total_pages总页数解析成功的页面列表长度
total_options总选项数所有页面options列表长度之和
total_examples总示例数所有页面examples列表长度之和
see_also跨引用数所有页面see_also列表去重排序后的长度

值得注意的是,Cross-references这一行是条件输出的:只有当see_also列表非空时才写入(man_scraper.py)。因此,当抓取的 man 页面全部没有 SEE ALSO 引用时,索引的统计段会少一行,黄金测试同样会验证这种边界。

三、从 man 页面到索引的完整管线

references/index.md只是产物链的最后一环,其上游是一条清晰的四级管线,全部封装在 man_scraper.py 的ManPageToSkillConverter中(该类继承自DocumentSkillBuilderSOURCE_TYPE = "manpage"):

  1. 提取(extract_manpages):从三个来源之一获取 man 页面原文——调用系统man命令、扫描目录中的.1.8/.man文件、或读取此前保存的中间 JSON;
  2. 清洗与解析:剥离 troff/groff 排版指令,将纯文本按 34 个标准节名(NAMESYNOPSISOPTIONSEXAMPLESSEE ALSOENVIRONMENT等,见 man_scraper.py)切分为结构化页面,并抽取optionsexamplessee_also
  3. 分类(categorize_content):把多页 man 文档聚合成若干分类(详见下一节);
  4. 生成:依次写出references/{cat}.md引用文件、references/index.md索引、SKILL.md技能入口。

提取结果会先以中间 JSON 落盘(默认路径由data_file_for()决定),打印格式为✅ Extracted N man page(s), M options, K examples。这样做的设计意图在模块 docstring 中有明确说明:把耗时且依赖系统环境的提取步骤与技能生成步骤解耦,便于--from-json直接复用之前的提取产物。

3.1 系统命令提取的细节

当使用--man-names时,_run_man_command()会执行man [section] <name>,并设置三个关键环境变量保证输出可解析:

  • MANWIDTH=999COLUMNS=999:避免终端宽度导致的换行折行;
  • MAN_KEEP_FORMATTING=0:关闭颜色转义。

命令执行设置了 30 秒超时;输出会再通过col -bx去除退格覆盖(backspace overstriking)格式,若系统没有col,则回退到正则.\x08手工删除退格符(man_scraper.py)。

3.2 目录扫描的细节

使用--man-path时,_extract_from_directory()会递归扫描目录,识别的扩展名集合为MAN_FILE_EXTENSIONS = {.1...{.8} } ∪ {.man, .1p, .3p},并支持.gz.bz2.xz三种压缩格式(读取时自动解压,文件名如git.1.gz会被剥离出git)。分区号通过_section_from_suffix()从扩展名推导(1p取首字符得到 1);若指定了--sections,不属于目标分区的文件会被过滤,但无分区后缀的.man文件不会被误删——这是 man_scraper.py 中特意处理的边界。

3.3 troff 清洗与结构化解析

_strip_troff_formatting()处理了 ANSI 转义、退格覆盖、.TH/.PP/.TP等宏指令、\fB字体切换、\-等特殊字符,最终把原文折叠为至多连续两个空行的纯文本。随后_parse_man_output()以"行首无缩进且内容匹配标准节名"为判定条件切分章节,并分别调用:

  • _extract_options():用正则匹配-f, --flag--long-option=VALUE等选项行,连续缩进行作为描述续行;
  • _extract_examples():以$#%>前缀或 4 空格缩进判定命令块,其余行视为描述文字,因此纯文字示例(无命令)也会被保留(golden 中 git-log 的 "Prose-only example with no command" 正是这种边界);
  • _extract_see_also():用([\w.+-]+)\s*\(\d+\)提取形如git-diff(1), gitk(1)的引用并去重排序。

四、分类机制:前缀分组、关键字分类与 other 兜底

索引中的 Categories 段直接由categorize_content()(man_scraper.py)决定,它支持三种模式,golden 目录用三个变体分别覆盖:

黄金树目录模式行为
tests/golden/phase2/man/自动前缀分组git-loggit-diff-为界取前缀git,归入同一分类;curl单独成类
tests/golden/phase2/man_kw/显式关键字分类按配置的categories关键字匹配页面,未命中任何分类的页面落入other兜底桶
tests/golden/phase2/man_single/单页模式只有一页时直接以页面名作为唯一分类,引用文件无编号

前缀分组并非无脑应用:只有当len(prefix_groups) < len(pages)(即分组确实能减少分类数量)时才启用;否则所有页面统一落入名为commands的分类(man_scraper.py)。这一设计避免了"每个前缀都是唯一前缀"时产生一堆无意义单页分类。

在关键字模式中,每个页面的descriptiontitle会被转为小写后与各分类关键字比对计分,得分最高的分类胜出;所有得分为 0 的页面进入other(标题为 "Other")。man_kw黄金树即用于验证该兜底路径的输出。

五、引用文件结构:git_01.md 与 curl_02.md

索引只是导航,真正的技术细节沉淀在分类引用文件中。以 git_01.md 为例,每个页面按_generate_reference_file()(man_scraper.py)固定输出以下小节:

  • 标题行## git-log(1),分区号存在时带(1)
  • NAME 行**git-log - Show commit logs**,当 title 与命令名相同(如curl)时该加粗行会被跳过;
  • Synopsis:放入无语言标注的代码块,例如git log [<options>] [<revision-range>] [[--] <path>...]
  • Description:超过 3000 字符时截断并追加*... (truncated)*(golden 中 git-diff 的超长描述正是验证点);
  • Options- \{flag}` -- {description}形式,单条描述超过 200 字符时截断(golden 中--max-count= ` 即演示了该截断);
  • Examples**Example N:** {description}加 bash 代码块,纯文字示例不输出代码块;
  • See Also:反引号包裹的引用列表;
  • 额外节:除NAME/SYNOPSIS/DESCRIPTION/OPTIONS/EXAMPLES/EXAMPLE/SEE ALSO之外的标准节(如ENVIRONMENTNOTES)会以### {节名}追加输出,超过 1500 字符截断,空节(仅空白字符)直接跳过——golden 中BUGS节为空白即验证了跳过逻辑。

curl_02.md 则演示了另一组边界:无分区号(标题行无(N))、title 与 name 相同(加粗行跳过)、无 synopsis(整节不输出)、无 SEE ALSO。

六、与 SKILL.md 的关系

索引不是孤立的。生成的技能目录中,SKILL.md 是面向 Agent 的入口:它以 YAML frontmatter 携带namedescription(描述由infer_description_from_manpages()从 NAME 行自动推断,形如 "Use when ..."),正文包含 When to Use、Quick Command Reference(汇总各页 synopsis)、Man Page Overview、Common Options(每命令最多展示 5 条、每条描述截断到 120 字符)、Examples(最多 15 条)、Related Commands (SEE ALSO)(最多 30 条)、Documentation Statistics 以及 Navigation。

Navigation 段会列出references/下的每个引用文件,并以See references/index.md for complete reference structure.指回本文主角——这正是 index.md 在整个技能产物中的定位:供人和 Agent 快速导航的目录页。注意 SKILL.md 底部保留了 "Generated by Skill Seekers | Man Page Scraper" 的水印,源码注释特别说明该拼写(Skill Seekers 而非 Skill Seeker)是刻意保留的,因为黄金树要求字节级一致。

七、CLI 参数与典型用法

man 技能生成可通过统一 CLI 的manpage子命令(解析器见 manpage_parser.py,参数定义见 arguments/manpage.py)或独立转换器调用。模块 docstring 给出三种典型用法:

# 方式一:按命令名抓取系统 man 页面 skill-seekers man --man-names git,curl --name unix-tools # 方式二:扫描本地 man 页面目录(无需系统安装 man) skill-seekers man --man-path /usr/share/man/man1 --name coreutils # 方式三:复用已提取的中间 JSON,跳过提取步骤 skill-seekers man --from-json unix-tools_extracted.json

参数说明(来自 arguments/manpage.py 与 arguments/create.py):

参数说明
--man-names逗号分隔的命令名,如ls,grep,find
--man-path包含 man 页面文件的目录路径
--sections逗号分隔的手册分区号,如1,3,8,与--man-path联用时过滤文件
--from-json从提取好的 JSON 直接构建技能

manpage 子命令的一个重要默认值是--enhance-level被强制设为0(默认禁用 AI 增强),因为 man 页面本身已经是结构化、高质量的内容,无需再走增强管线;需要时仍可手动提升增强级别。

八、黄金测试如何保证输出契约

tests/golden/phase2/man/下的文件来自旧版(DocumentSkillBuilder重构之前)代码的真实输出。tests/test_phase2_golden_man.py通过assert_matches_golden(build_snapshot(converter), "man")将当前转换器重建的产物与该目录逐字节比对——因此任何对生成格式的无意改动(哪怕一个空格、一个空行)都会让测试失败。

该测试的PAGES数据构造了几乎所有生成分支(test_phase2_golden_man.py):

  • 分区号存在与缺失(git-log(1)vscurl);
  • title 与 name 相同/不同(curl 跳过加粗行);
  • 缺失 synopsis(curl 不输出 Synopsis 节);
  • 超过 3000 字符的描述截断(git-diff)与超过 1500 字符的额外节截断(NOTES);
  • 超过 200 字符的选项描述截断(--max-count);
  • 纯文字示例(无命令);
  • 空白节跳过(BUGS);
  • options/examples/see_also

三个变体(manman_kwman_single)分别锁定"前缀分组 + 多分类编号文件"、"关键字分类 + other 兜底"、"单页单分类无编号文件"三条路径。若你要为技能产物开发解析器、渲染器或索引器,这些 golden 文件就是最可靠的格式规范来源。

九、扩展与边界:把 man 技能接入更大工作流

理解了索引与引用文件的结构后,可以进一步利用 Skill Seekers 的既有能力:

  • 冲突检测与安装:生成后的技能目录可通过项目的 install/packaging 流程落地,例如用 安装指南 与 打包说明 将 man 技能与其他来源(文档网站、GitHub 仓库、PDF)生成的技能统一管理;
  • 检索与增强:man 技能产出的是纯 Markdown,天然适配 技能索引 与嵌入管线(embedding),可被 RAG 工作流直接消费;
  • 回归验证:修改生成逻辑后运行 test_phase2_golden_man.py,即可快速确认 man 输出的三类黄金树是否仍保持字节级一致。

需要留意的是,本项目的 man 提取依赖运行环境:--man-names需要系统安装man与对应手册页(缺失时返回None并跳过该页),--man-path则无此限制;压缩格式、POSIX 扩展名(1p/3p)与递归子目录(man1/man2/)均已被支持,适合在不便安装手册页的容器环境离线生成技能。

十、小结

tests/golden/phase2/man/references/index.md虽是一份测试基准,但它精确地记录了 Skill Seekers man 页面转技能管线的三个核心设计:

  1. 以分类为组织的导航结构——分类命名规则({cat_key}_{NN}.md)与All Man Pages的排序、分区标注方式;
  2. 可解释的统计口径——total_pagestotal_optionstotal_examplessee_also四个指标全部源自提取阶段的真实解析结果;
  3. 条件输出与边界处理——Cross-references条件行、无分区页面、纯文字示例、空白节跳过等细节共同构成了输出的稳定性。

配合 man_scraper.py 的extract → parse → categorize → generate四阶段实现与 test_phase2_golden_man.py 的分支覆盖,你可以放心地把这份结构当作解析、渲染或二次开发 man 技能产物的格式契约。

【免费下载链接】Skill_SeekersConvert documentation websites, GitHub repositories, and PDFs into Claude AI skills with automatic conflict detection项目地址: https://gitcode.com/gh_mirrors/sk/Skill_Seekers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询