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 页面按照分类聚合后的引用文件组织起来,形成三类信息:
- Categories(分类清单)——列出每个分类及其对应的引用文件,例如
[Git](https://link.gitcode.com/i/0bd7801b34e8d2d96ee9a45b4e0fbd64) (2 man page(s)); - All Man Pages(全量页面清单)——按名称排序列出每一页的命令名与标题,例如
git-diff(1) -- git-diff - Show changes between commits; - 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}.md,cat_num从 1 开始递增。
本示例有git与curl两个分类,因此得到git_01.md与curl_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-diff、git-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中(该类继承自DocumentSkillBuilder,SOURCE_TYPE = "manpage"):
- 提取(extract_manpages):从三个来源之一获取 man 页面原文——调用系统
man命令、扫描目录中的.1–.8/.man文件、或读取此前保存的中间 JSON; - 清洗与解析:剥离 troff/groff 排版指令,将纯文本按 34 个标准节名(
NAME、SYNOPSIS、OPTIONS、EXAMPLES、SEE ALSO、ENVIRONMENT等,见 man_scraper.py)切分为结构化页面,并抽取options、examples、see_also; - 分类(categorize_content):把多页 man 文档聚合成若干分类(详见下一节);
- 生成:依次写出
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=999与COLUMNS=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-log、git-diff以-为界取前缀git,归入同一分类;curl单独成类 |
tests/golden/phase2/man_kw/ | 显式关键字分类 | 按配置的categories关键字匹配页面,未命中任何分类的页面落入other兜底桶 |
tests/golden/phase2/man_single/ | 单页模式 | 只有一页时直接以页面名作为唯一分类,引用文件无编号 |
前缀分组并非无脑应用:只有当len(prefix_groups) < len(pages)(即分组确实能减少分类数量)时才启用;否则所有页面统一落入名为commands的分类(man_scraper.py)。这一设计避免了"每个前缀都是唯一前缀"时产生一堆无意义单页分类。
在关键字模式中,每个页面的description与title会被转为小写后与各分类关键字比对计分,得分最高的分类胜出;所有得分为 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之外的标准节(如ENVIRONMENT、NOTES)会以### {节名}追加输出,超过 1500 字符截断,空节(仅空白字符)直接跳过——golden 中BUGS节为空白即验证了跳过逻辑。
curl_02.md 则演示了另一组边界:无分区号(标题行无(N))、title 与 name 相同(加粗行跳过)、无 synopsis(整节不输出)、无 SEE ALSO。
六、与 SKILL.md 的关系
索引不是孤立的。生成的技能目录中,SKILL.md 是面向 Agent 的入口:它以 YAML frontmatter 携带name与description(描述由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。
三个变体(man、man_kw、man_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 页面转技能管线的三个核心设计:
- 以分类为组织的导航结构——分类命名规则(
{cat_key}_{NN}.md)与All Man Pages的排序、分区标注方式; - 可解释的统计口径——
total_pages、total_options、total_examples、see_also四个指标全部源自提取阶段的真实解析结果; - 条件输出与边界处理——
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),仅供参考