1 - 管理资料库
资料库是 Crib 里已安装的全部文档。打开方式:菜单“资料库 → 管理资料库…”、工具栏的资料库按钮,或主页的“资料库”。菜单“资料库 → 获取更多版本…”和主页的“获取版本”直接打开“全部版本”。
已安装与全部版本
顶部的分段控件切换两种列表:
| 列表 | 内容 |
|---|---|
| 已安装 | 这台 Mac 上的资料包,包括已停用的 |
| 全部版本 | 已安装的,加上版本目录里还没安装的;未安装的行显示下载大小和安装后大小 |
列表按版本状态分组(默认、常规、历史版本……),含义见版本与别名。每行还标出来源(内置或自行安装)、占用空间,以及是否在当前搜索范围内。
筛选框接受版本号或别名,例如 18、pg17、[email protected]。输入能解析成一个确切版本的别名时,列表只显示那一项。
专家模式
专家模式默认关闭,这时列表只显示“默认”和“常规”两组。打开后,列表还显示历史版本、开发版、无法下载和状态未知的版本,不加版本前缀的搜索也会包含它们。
资料库和正文上方的“版本”弹窗里各有一个“专家模式”开关,两处改的是同一个设置。
启用与停用
已安装的每一行左侧有一个勾选框。勾选或取消后,行内显示“应用后启用”或“应用后停用”,底栏显示“有未应用的更改”。点“应用更改”生效,点“放弃更改”撤回。
- 同一个资料包只能启用一个修订。勾选某个修订时,同一资料包的其他修订会自动取消勾选。
- 已停用的行右侧有“启用”按钮,点它立即生效,不需要再点“应用更改”。
- 停用的版本仍在磁盘上,但不参与搜索,也不能从列表打开阅读。
应用更改时发生什么
- Crib 用勾选的资料包在后台建立一个新的搜索世代(generation)。进度面板依次显示“下载 → 校验 → 建立索引 → 启用”;不需要下载时从“校验”开始。
- 建立期间,旧的搜索世代照常提供搜索和阅读。点“继续阅读”可以关掉资料库窗口,任务在后台继续。
- 新世代建好后原子切换。之后的搜索使用新组合;已经打开的页面继续显示打开时的版本。
切换前点“取消”,旧组合保持不变。失败时资料库显示原因和“重试”。
卸载
只有自行安装的资料包有“卸载”按钮。App 内置的资料包不能卸载,只能停用。
卸载分两步:
- Crib 先切换到一个不含该资料包的组合,这一行标为“待移除”,显示“不再用于阅读和恢复后即可清理”。
- 文件在执行“维护 → 清理不再需要的资料”时删除,前提是没有打开的页面、当前组合或保留的旧组合还在使用它。
卸载不删除笔记、书签和更正。指向已卸载内容的个人资料会保留,内容重新安装后可以再次定位。
导入资料包
点资料库右上角的“导入资料包…”,选择一个 .crib 文件(旧扩展名 .pgdocpack 也可以),或一个已解开的资料包文件夹。导入不需要联网。
Crib 先检查磁盘空间,再解包并逐项校验:签名必须由 App 自带的可信根签发,每个文件的哈希必须与清单一致,数据库结构必须符合格式。通过后,新资料包立即启用,并替换同一资料包当前启用的修订。
以下情况会被拒绝:
- 与已安装的资料包同名同修订、内容却不同。
- 修订号低于当前启用的修订。要回到旧修订,用下面的“恢复资料组合…”。
- 签名密钥不在可信根里,或是开发密钥签名而当前构建不接受开发内容。
现在没有公开发布的资料包。开发构建只能导入用开发密钥签名的测试资料包。格式见资料包格式。
恢复资料组合
每次切换组合时,Crib 保留切换前启用的那一组,以便回退;更早的组合会被释放。
- 点底栏的“恢复资料组合…”,从菜单中选一个保留的组合。
- 预览窗口列出“现在启用 N 项,恢复后启用 M 项”,以及要启用、停用或替换的资料包、修订和语言。
- 点“恢复”。Crib 先完整校验目标组合,再切换。
- 资料库里有未应用的更改时不能恢复,先应用或放弃它们。
- 预览打开后如果组合被别的操作改变,点“刷新预览”后再确认。
- 已打开的页面、笔记和书签不受影响。
维护菜单
| 命令 | 作用 |
|---|---|
| 清理不再需要的资料 | 删除待移除的资料包,以及不再被当前组合、保留组合或打开的页面使用的搜索世代 |
| 备份个人资料… | 把笔记、书签、标签、阅读历史和更正备份成一个 SQLite 文件,见备份个人资料 |
启动时的修复提示
Crib 启动时如果发现当前组合不能用(例如 App 换新后原来内置的资料包不在了,或搜索世代损坏),会自动换到一个可用的组合,并在资料库顶部留一条提示,直到你点“知道了”。提示带“重新启用”按钮时,可以把之前启用的资料包重新启用。
“非正式发布”标记
资料库标题旁的“非正式发布”标记表示:这些资料用开发密钥签名,只用于本地测试。构建声明接受开发内容,或 App 自带的可信根是开发可信根时,就会显示这个标记。
Crib 还没有正式签名密钥,现在所有开发构建都会显示它。
2 - 版本与别名
收录的版本线
Crib 收录 31 条 PostgreSQL 手册版本线,每条一个中英双语资料包;Wiki 是另一个资料包。默认版本是 PostgreSQL 18(18.6),也是 pg 别名的目标;只内置一个版本的构建内置的就是它。
| 版本线 | 内容版本 | 别名 |
|---|---|---|
| 6.3 – 6.5 | 6.3.2、6.4.2、6.5.3 | pg63 … pg65,或 pg6.3 … pg6.5 |
| 7.0 – 7.4 | 7.0.3、7.1.3、7.2.8、7.3.21、7.4.30 | pg70 … pg74,或 pg7.0 … pg7.4 |
| 8.0 – 8.4 | 8.0.26、8.1.23、8.2.23、8.3.23、8.4.22 | pg80 … pg84,或 pg8.0 … pg8.4 |
| 9.0 – 9.6 | 9.0.23、9.1.24、9.2.24、9.3.25、9.4.26、9.5.25、9.6.24 | pg90 … pg96,或 pg9.0 … pg9.6 |
| 10 – 14 | 10.23、11.22、12.22、13.23、14.24 | pg10 … pg14 |
| 15 – 18 | 15.19、16.15、17.11、18.6 | pg15 … pg18 |
| 19 | 19rc1(预览版) | pg19 |
| 20 | 20devel(开发快照) | pg20、pgdevel |
| Wiki | r5 | pgwiki |
内容版本来自构建时固定的来源快照,不代表上游当前的最新小版本。
版本状态
版本目录给每个版本声明一种状态。状态由发布者写进签名目录,Crib 不按版本号、发布渠道或是否已安装去推断。
| 目录中的值 | 界面显示 | 普通列表和不带版本前缀的搜索 | 下载 |
|---|---|---|---|
default | 默认 | 包含 | 可以 |
active | 常规 | 包含 | 可以 |
historical | 历史版本 | 只在专家模式下包含 | 可以 |
devel | 开发版 | 只在专家模式下包含 | 可以 |
unavailable | 无法下载 | 只在专家模式下包含 | 不能;已安装的照常阅读和搜索 |
| (未声明) | 状态未知 | 只在专家模式下包含 | 可以 |
- 目录里只有一个默认版本,就是
pg指向的那个。开发版不能成为默认版本。 - “常规”只表示出现在普通列表里,不表示上游仍在维护。
- “状态未知”出现在不带状态字段的旧格式目录里。旧目录指定的默认版本仍出现在普通列表。
- 状态只决定版本出现在哪里、能不能新下载,不影响已安装内容的可读性。显式指定版本(版本前缀、版本菜单、书签、已打开的页面)照常可用,只要该版本已安装并启用。
- 还没有任何版本目录时,不带版本前缀的搜索只覆盖 App 内置的资料包。
本页不列出各版本的状态。状态由发布者在签名目录中决定,正式目录还没有发布。
列表里还会出现另一组状态:已启用、已停用、未安装、目录已过期、不在目录中、失败、待移除。它们描述这台 Mac 上的安装情况和最近一次操作,与上表的发布状态互相独立。
别名怎样解析
别名只存在于版本目录中,不对应额外的文件。解析规则:
- 输入转成 ASCII 小写,
PG18与pg18相同。含非 ASCII 字符的输入不是别名。 - 沿目录中的别名链一直走到一个确切版本,格式是
项目@内容版本,例如[email protected]。链不能有环,目标必须存在。 - 在这个版本里选出包含所需语言的资料包。现在每个版本是一个中英双语包。
| 输入 | 解析路径 |
|---|---|
pg | pg → pg18 → [email protected] |
pg18 | pg18 → [email protected] |
pg96 | pg96 → [email protected] |
pg9.6 | pg9.6 → pg96 → [email protected] |
pg19 | pg19 → pg@19rc1 |
pgdevel | pgdevel → pg20 → pg@20devel |
pgwiki | pgwiki → pgwiki@r5 |
[email protected] | 本身就是确切版本 |
pg是唯一的总别名,指向发布者选定的默认版本线。pg19、pg20不会自动变成pg。pg18这类版本线别名指向该线当前发布的小版本。版本号含点的旧版本线同时接受带点写法,如pg9.6、pg7.0。- 解析只读本机已缓存并校验过的目录,不需要联网。
别名不会换成别的小版本
别名总是解析到一个确切版本。目标不可用时,Crib 说明原因,不会改用同一版本线上已安装的其他小版本:
| 目标状态 | 搜索时的提示(以 18.7 为例) |
|---|---|
| 未安装 | PG18(18.7)未安装,请在资料库中下载后再搜索。 |
| 已停用 | PG18(18.7)未启用,请在资料库中启用后再搜索。 |
| 无法下载且未安装 | PG18(18.7)已无法下载,请改用已安装的版本。 |
假设发布者把 pg18 从 18.6 移到 18.7,而你只装了 18.6:资料库在“全部版本”里显示 18.7 未安装;已安装的 18.6 仍可用 [email protected] 或版本菜单打开。
发布新的小版本时,发布者新增一个文件和一条版本记录,再移动对应的版本线别名;18.6 的文件不会被覆盖或改名。只移动别名不会重建搜索索引,也不会改变已打开的页面。
在哪里用别名
- 搜索框的版本前缀:
PG18: vacuum、pg96: vacuum、[email protected]: max_connections lang:en。pg18:vacuum与pg18: vacuum相同。 - 资料库的筛选框。
- 本地 API 和 MCP 的搜索文本。
3 - 下载、更新与恢复
Crib 默认从 https://repo.pigsty.io/doc/catalog.json 获取版本目录。这个地址是规划中的正式目录,还没有上传,所以现在“刷新目录”拿不到正式目录。下文描述开发构建的行为,在本机测试目录上验证过,没有在公网 HTTPS 和 CDN 上测试。
什么时候联网
打开 Crib 或资料库都不联网。只有两个操作会联网:点“刷新目录”,以及点某个版本的“下载”。
已安装的内容不会过期,阅读和搜索始终离线完成。导入本地资料包也不需要联网。
版本目录
版本目录(catalog.json)列出可下载的版本、它们的状态、别名,以及每个归档的大小和哈希。开发构建可以内置一份签名的目录快照,所以第一次打开、没有联网时也能看到全部版本。
点“刷新目录”时,Crib 下载新目录并检查:
- 签名必须由 App 自带的可信根签发。服务器不能自己添加可信密钥。
- 修订号不能低于本机已有的目录;修订号相同而内容不同,只接受签发时间更晚的一份。否则视为回退或冲突,保留原来的目录。
- 已过期的目录不接受。
刷新失败不改动本机文件。资料库顶部显示“版本目录更新于 …”;刷新中可以点“取消”。
目录过期以后
目录带有效期,由发布者签名时写入。过期后,资料库显示“版本目录已过期,刷新后才能下载。”
- 版本列表照常显示,别名照常解析。
- 不能下载新版本,直到刷新到一份未过期的目录。
- 已安装的内容不受影响。
本机缓存的目录如果无法再通过校验(例如可信根换了密钥),Crib 跳过它,改用 App 内置的快照,并把旧文件移到用户目录的Distribution-rejected/,保留最近 5 份。目录中个别条目有问题时,只忽略那些条目,并在资料库提示;已安装的同一版本照常可读。
下载一个版本
在“全部版本”里点某一行的“下载”。进度面板显示“下载 → 校验 → 建立索引 → 启用”,下载阶段显示已下载和总字节数。
- 确认授权。 该版本必须在一份未过期的目录里,且状态不是“无法下载”。归档路径必须是目录给出的相对路径,只走同源 HTTPS,不跟随跨站重定向。
- 流式下载。 写入临时目录,总字节数以目录签名的大小为准。
- 校验。 核对长度、归档 SHA-256、ZIP 结构、清单哈希(必须等于目录记录的值)、清单签名、解包后的总大小。
- 解包。 解到暂存区,再逐个文件核对哈希并检查数据库结构。传输结束后再确认一次目录仍然授权这个版本。
- 建立索引。 在后台建立新的搜索世代,旧世代继续服务。
- 启用。 原子切换。新版本替换同一资料包当前启用的修订;旧修订仍已安装,状态变为“已停用”。
下载、校验或索引失败时,按钮变为“重试下载”。
断点续传
- 网络中断时(不包括你点“取消”),已下载的部分保存在用户目录的
Distribution-partials/中,保留 7 天。 - 再次下载同一个归档时,Crib 先重新计算已保存部分的哈希,再用
Range加If-Range(强 ETag 或 Last-Modified)请求剩余部分。 - 服务器返回 206 时必须带完全匹配的
Content-Range;返回 200 就从头重下。最终仍以目录签名的归档哈希为准。 - 点“取消”,或者校验、大小、路径检查失败时,已下载的部分直接丢弃。
- 单次下载最长 48 小时;连续 60 秒收不到数据视为中断,已下载部分保留以便续传。目录请求最长 600 秒。
失败、取消与磁盘空间
- 切换之前的任何失败、取消或磁盘空间不足,都保留原来的组合,不做切换。
- 资料包写入资料库之前先检查磁盘空间。
- 切换一旦完成,新组合就是当前组合,即使之后又报告了错误。重试前先看资料库里实际启用的是什么。
- 失败只记在这一个版本上。之前启用的旧修订照常可读。
更新到新的小版本
发布者发布新的小版本时,新增一个归档并移动版本线别名,例如把 pg18 从 18.6 移到 18.7;18.6 的文件不变。
刷新目录后,“全部版本”里出现 18.7,状态为未安装。刷新本身不会自动下载,也不会重建索引。下载 18.7 后,它替换 18.6 成为启用的修订;18.6 仍已安装,可以重新启用,也可以卸载。
下载或导入同一资料包中比当前启用修订更低的修订会被拒绝。要回到以前的修订,用“恢复资料组合…”。
Crib 没有自动更新。App 本身也没有公开的更新通道。
回到以前的组合
每次切换组合,Crib 保留切换前启用的那一组。在资料库底栏点“恢复资料组合…”可以预览并恢复,步骤见管理资料库。
启动时如果当前搜索世代损坏,或 App 换新后原来内置的资料包不在了,Crib 自动换到保留的组合或 App 内置的初始组合,并在资料库顶部提示。提示里的“重新启用”可以把之前启用的资料包重新启用。
个人资料不受影响
下载、导入、启用、停用、卸载和恢复组合都不写个人资料:笔记、书签、标签、阅读历史、更正、片段和设置。卸载一个版本后,挂在上面的笔记和书签保留;内容重新安装后可以再次定位。
4 - 资料包格式
现在没有公开的资料包,也没有正式签名密钥。发布目录规划在 https://repo.pigsty.io/doc/,还没有上传。本页描述开发构建和构建工具 crib-pack 实现的格式。
文件
资料包是一个 ZIP 文件(支持 ZIP64,条目为 stored 或 DEFLATE),条目按名称排序,时间戳固定。2026-11-06 起新发布的资料包以 .crib 结尾;之前签发的目录和归档使用 .pgdocpack,这些已签名的路径继续有效。版本目录里的归档路径只接受这两种结尾,.CRIB、.crib.zip 等都会被拒绝。
App 还没有注册 .crib 文件类型,双击不能导入;请用资料库的“导入资料包…”。
一个手册资料包的内容:
pg/18.6-r4.crib
- manifest.json清单:身份、版本、语言、文件列表与每个文件的哈希
- manifest.sig对 manifest.json 原始字节的 Ed25519 签名
- sources.json来源:上游修订、版次、修复记录和处理说明
- content.sqlite文档、章节、精确名称键、双语对应、链接和搜索词元
- documents/
- en/英文 HTML 与资源
- zh-Hans/简体中文 HTML 与资源
- licenses/许可文本,按语言分目录
Wiki 资料包的页面在 documents/<语言>/wiki/<集合>/ 下,另外带有原始来源记录和许可说明 licenses/center-sources.json。
清单
format_version- 资料包格式,现在是
1 schema_versioncontent.sqlite的结构版本,现在是1analyzer_id- 分词器标识
pgdash-han2-v1;旧名称属于格式身份,不随产品改名 pack_id- 资料包身份,如
postgresql/manual/18、postgresql/wiki project_id、branch、content_version、channel- 项目、版本线、内容版本、发布渠道
pack_revision- 修订号,同一
pack_id跨内容版本单调递增 languages["en", "zh-Hans"]min_reader_version- 能读取它的最低 Crib 版本
source_manifest_sha256sources.json的哈希files- 除清单和签名外每个文件的
path、bytes、sha256 licenses- 许可文件路径
trust- 签名类别;开发构建中是
development
清单之外出现未声明的文件,或任何文件与清单哈希不符,资料包都会被拒绝。Crib 用 manifest.json 原始字节的 SHA-256 标识一个已安装的资料包,链接里的 manifest 参数就是这个值。
签名与可信根
manifest.sig 是 {"key_id": "…", "signature": "<base64>"},签名对象是 manifest.json 的原始字节。目录 catalog.json 用同样的 Ed25519 签名。
公钥只来自 App 自带的 trust.json。资料包或服务器里的密钥都不会被信任。
key_policies可选。roles取pack、seed、catalog的子集;not_after必须是YYYY-MM-DDTHH:MM:SSZ。没有列出的密钥可签所有用途、永不过期。- 未知字段、空的
roles、不规范的日期、指向不存在密钥的策略都会让整个可信根被拒绝。 - 密钥过期只阻止获取(刷新目录、下载、导入)和发布端签名,已安装的内容照常可用。
- 从可信根删除密钥等于吊销。要退役一把密钥,先设
not_after。
开发签名的内容只在两种情况下被接受:构建在 Info.plist 中声明 CribDevelopmentContent=true,或测试环境设置CRIB_ALLOW_DEVELOPMENT_CONTENT=1。这时资料库显示“非正式发布”。
导入与下载时的检查
解包之前,Crib 先完整检查整个 ZIP,拒绝符号链接、特殊文件、加密条目、分卷、路径穿越、大小写或 Unicode 规范化后重名的路径、多余的尾部字节。
| 上限 | 值 |
|---|---|
| 条目数 | 65,000 |
| 单个文件 | 8 GiB |
| 解包后总大小 | 16 GiB |
| 压缩文件 | 20 GiB |
| 压缩比 | 1000:1 |
然后核对签名、每个文件的哈希、数据库结构和引用。同一 pack_id 同一修订号而内容不同的资料包会被拒绝。从目录下载时还要核对归档长度和 SHA-256、清单哈希和解包后大小,它们必须与目录记录一致。
发布目录
https://repo.pigsty.io/doc/(规划中)
- catalog.json签名目录:别名、版本与状态、每个归档的路径、大小和哈希
- pg/
- 18.6-r4.crib
- 17.11-r4.crib
- 9.6.24-r4.crib
- 20devel-r4.crib
- pgwiki/
- r5.crib
完整目录有 31 个手册归档和 1 个 Wiki 归档。文件名是内容版本加修订号。别名只写在 catalog.json 里,不复制文件,也不建符号链接。
catalog.json 是一个签名信封,解码后的载荷包含目录身份、修订号、签发和过期时间、默认别名、别名表和版本表:
这是节选,正式载荷还有 generated_at、expires_at、大小、结构版本等字段。版本状态 lifecycle 的含义见版本与别名。
客户端只使用目录给出的归档路径:一级目录加一个文件名,不接受绝对地址、查询串、片段、百分号转义、反斜杠和 ..,下载走与目录同源的 HTTPS。
不可变规则
- 同一个 URL 的字节永远不变。内容有任何更正,都发新的内容版本或更高的修订号。
- 修订号按
pack_id单调递增,换内容版本也不重置:18.6-r4 之后发布 18.7,修订号至少是 r5。 - 先上传并核对所有新归档,最后再替换
catalog.json。 - 目录修订号只增不减。
crib-pack distribute的--previous-catalog要求新修订号更大;--validity设定目录有效期,默认 720 小时,范围 24 小时到 400 天。
HTTP 缓存
这些是发布端的要求,还没有在真实服务器上配置和测试。
| 对象 | 响应头 |
|---|---|
catalog.json | Cache-Control: no-cache |
| 带版本和修订号的归档 | Cache-Control: public, max-age=31536000, immutable,Content-Length,强 ETag,支持 Range,不做内容转换 |
客户端续传时发送 Range 和 If-Range,规则见断点续传。