跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

快速上手

从官方 OINK Starter 建立可运行的本地基线,再依次定制内容、语言、品牌、集成与部署。

新站点的推荐起点是 pgsty/oink-starter,而不是复制本站这个 文档与回归测试仓库。Starter 是公开的 GitHub 模板:它固定一个已发布的 OINK 版本,默认即可构建,只包含中性的项目示例与部署 workflow。

两个版本号承担不同职责

OINK 声明的兼容性下限是 Hugo Extended 0.160.1。当前 Starter 与它的 CI 固定使用 Hugo Extended 0.165.0 和 Go 1.27。下面这条路径应 使用 Starter 固定的工具链;只有刻意维护旧环境的既有站点才使用较低的兼容下限。

选择起点

当前情况 推荐路径 得到什么
新建文档站或项目站 OINK Starter 一套精简的三语 Docs、Blog、Book 站点与两条部署 workflow
已有 Hugo 站点 从零安装 不替换内容,只补 OINK 模块与 Goldmark 前置配置
已有 Docsy 或旧版 OINK 站点 版本升级 保留内容,迁移受支持的语法,并审查站点覆盖

五分钟建立基线

  1. 安装工具

    安装 Git、Go 1.27 或更新版本,以及 Hugo Extended 0.165.0 或更新版本。Hugo 输出必须包含 extended:

    $ go version
    go version go1.27.0 darwin/arm64
    $ hugo version
    hugo v0.165.0+extended+withdeploy darwin/arm64
    

    macOS 可以执行 brew install git go hugo。Linux 与 Windows 请按官方 Hugo 安装指南和 Go 下载页安装,并确认选择 Hugo Extended。

  2. 创建或克隆站点

    准备长期维护时,请打开 Starter 仓库并点击 Use this template,然后克隆 GitHub 为你创建的新仓库。只想在本机评估原始模板时执行:

    git clone https://github.com/pgsty/oink-starter.git my-docs
    cd my-docs
    hugo server
  3. 打开基线

    打开 http://localhost:1313/。默认 Starter 还在 /zh/ 发布中文,在 /fr/ 发布法语。开始修改前,先确认 Docs、Blog、Book、本地搜索、语言切换与深浅色 模式都能工作。

  4. 完成一个可见修改

    修改 hugo.yaml 顶部的站名与规范 URL,再修改 data/home/en.yaml 中的一句话。 浏览器刷新后能同时看到两处变化,才算证明配置、内容与固定版本的主题已经正确连通。

由浅入深地定制

  • 使用 OINK Starter — 先选语言,再依次处理身份、首页、 内容、导航、品牌、集成与部署。
  • Starter 仓库导览 — 每个文件负责什么,哪些要替换, 哪些可以删除。
  • 编写页面 — front matter、标题、链接、图片、草稿与页尾控件。
  • 组件总览 — 内容树稳定后,再增加表达能力。
  • 品牌外观 — Logo、强调色、字体、页宽与 CSS 扩展点。
  • 发布上线 — 使用内置 GitHub Pages 或 Cloudflare Pages workflow,再验证真实公开路由。

这个顺序是有意的。先证明构建与内容树,再逐项增加定制,比同时修改语言、导航、 CSS、分析与托管更容易定位问题。

发布门禁

第一次推送前,执行与 Starter workflow 相同的严格生产构建:

hugo --cleanDestinationDir --gc --minify --environment production \
  --printPathWarnings --panicOnWarning

命令以 Total in … 结束、没有警告或错误,而且 public/ 中存在各语言根与代表性的 Docs、Blog、Book 路由,才算通过。此时仍只证明本地构建:本地构建、提交、推送、 workflow 变绿与公开站点正确,是彼此独立的关卡。

下一步

继续阅读完整 Starter 教程。如果模板有你不需要的结构, 按仓库导览安全删减。只有在给既有站点接入 OINK,或者 明确想亲手组装每个文件时,才走从零建站路径。

1 - 使用 OINK Starter

按语言、身份、首页、内容、导航、品牌、集成、部署的顺序,把官方 Starter 逐层变成你的项目站点。

pgsty/oink-starter 是新建 OINK 站点的正式起点。它刻意小于 oink.pgsty.com:不会把主题文档、分析账号、评论仓库、 浏览器回归套件或 PGSTY 品牌复制进你的项目。

截至 2026-09-20,模板固定 OINK v1.0.0、Go 1.27 与 Hugo Extended 0.165.0。 默认三语、仅英文、英中双语三个 profile 都已经在这个版本上完成 warning 即失败的 严格构建。

模板包含什么

内容区 内置基线 第一个决定
语言 英语、简体中文、法语 保留三语,或选择内置单语 / 双语 profile
内容 Docs、Blog 与一本简短 Book 教程 重写示例;确认整个内容区不需要时才整棵删除
首页 每种语言一份精简 data/home/<lang>.yaml 替换项目承诺与入口
品牌 中性 Logo 与 favicon 有正式项目图形之前先保留
集成 仓库、Giscus、分析、分享、反馈示例均被注释 只启用你准备长期运营的完整配置
部署 GitHub Pages 与 Cloudflare Pages Direct Upload workflow 选择一条生产路径并验证真实 URL

Starter 自己的 /book/ 是一份从预览到部署的四章短教程。本页是维护者级版本: 说明修改顺序、各层边界,以及每层之后应执行的检查。

创建自己的仓库

推荐使用 GitHub 模板

打开 Starter 仓库,点击 Use this template → Create a new repository,再克隆 GitHub 在你的账号或组织下 创建的仓库:

git clone https://github.com/OWNER/PROJECT-DOCS.git
cd PROJECT-DOCS
hugo server

这样站点从一开始就有自己的 Git 历史,原始 Starter 只是上游参考,不会成为一个 可能误推送的 remote。

克隆原始仓库进行评估

只做一次性本地评估时执行:

git clone https://github.com/pgsty/oink-starter.git
cd oink-starter
hugo server

真实项目不要从删除这个 clone 的 .git 目录开始。GitHub 模板操作已经创建了清晰的 项目边界,并保留可审计的初始提交。

修改前先预览

依次打开:

  • /、/zh/、/fr/:三个首页;
  • /docs/、/blog/、/book/:三种内容区;
  • 任意一组译文,再操作语言切换器;
  • 本地搜索、深浅色切换,以及一个窄屏视口。

同时记录实际解析的模块:

hugo mod graph | grep github.com/pgsty/oink

本文记录的模板快照 137843b 固定 github.com/pgsty/[email protected]; 如果模板后来更新,以你克隆出的 go.mod 为准。这份未修改的预览是后续改动的基线。 先完成首次预览,再单独按1.0 → 1.1 升级核对项 升级仍使用 1.0 的站点,不要把主题升级与首次内容定制混在一次操作里。

分层定制

第一层:语言配置

根配置默认启用英语、中文和法语。如果这不是目标语言组合,请在其它配置修改之前 选择内置 profile。以下两条命令二选一:

cp examples/hugo.single.yaml hugo.yaml     # 仅英文
cp examples/hugo.bilingual.yaml hugo.yaml  # 英文 + 中文

这两份是完整的最小配置,不是可以叠加的片段;复制会覆盖根文件里那些被注释的集成 示例。因此应在最开始做;hugo.yaml 已有项目修改时,只合并 languages 与 disableLanguages,不要整文件覆盖。

如果已按快速上手修改站名与 URL,不必复制整份 profile。默认三语改为英中双语时, 只需在现有 hugo.yaml 顶层加入 disableLanguages: [fr];仅英文则使用 [zh, fr]。 这样可以保留已完成的身份与集成配置。

未启用语言仍保留声明,让 Hugo 能识别 .zh.md 与 .fr.md 是译文并安全忽略。 要永久移除一种语言,先确认所选 profile 能构建,再删除对应内容与首页数据。

第二层:站点身份

修改 hugo.yaml 顶部标有 CHANGE ME 的两个值:

hugo.yaml
title: &siteTitle Project Name
baseURL: https://example.org/

标题的 YAML 锚点会把站名带进所有已启用语言。接着修改版权人,并在新仓库已存在后 取消仓库链接的注释:

hugo.yaml
params:
  copyright:
    authors: '[项目贡献者](https://example.org/community/)'
    from_year: 2026
  github_repo: https://github.com/OWNER/PROJECT-DOCS
  github_branch: main

重新运行 hugo server,检查浏览器标题、页脚、编辑 / 历史链接与 canonical URL。 项目图形尚未定稿时先不要改 Logo;文字身份更容易先完成评审。

第三层:首页

首页是数据,不是难以维护的整页模板覆盖:

data/home/en.yaml
data/home/zh.yaml
data/home/fr.yaml

先改一种语言。每个文件里的 sections 决定顺序,hero、cards、cta 提供内容。 保持结构,替换项目承诺、目标 URL 与示例卡片。第一种语言确认无误后,再把同一组事实 翻译到已启用语言。

需要其它组合时,使用首页与落地页中的完整注册表;不要复制 Starter 的首页 partial,因为这里本来就没有站点自有模板。

第四层:内容与导航

重写或删除 content/ 下的示例叶子页面。确定整个内容区不属于你的项目之前,先保留 栏目根:

content/docs/  参考与任务文档
content/blog/  文章、设计记录与发布说明
content/book/  连续阅读的长篇指南

内容树就是侧栏。顶部导航写在各语言 _index 根页的 menus.main 里,因此给 Docs、 Blog 或 Book 改名时,修改发生在它所描述的内容旁边,而不是另一棵全局菜单树。译文 并排放置,对应标题使用相同的显式 ID:

page.md
page.zh.md
page.fr.md

新增自定义导航数据之前,先读组织内容;大多数站点使用生成树 已经足够。

第五层:品牌与阅读功能

正式图形准备好后,替换 assets/icons/logo.svg 与 static/favicon.svg。随后一次只启用 一组最小而有用的配置:

hugo.yaml
params:
  ui:
    theme_color: '#245f94'
    typography: system
    image_zoom: true
    share: [mastodon, linkedin, email, copy]

自定义本地字体时,用 params.ui.fonts 写字体族,或者在站点 CSS 中声明字体文件。 布局、侧栏、搜索与组件配置应查询配置总览,不要复制 oink.pgsty.com 那份大得多的站点配置。

第六层:外部集成

Starter 默认关闭或注释了仓库操作、Giscus、Google Analytics、反馈与分享。只有 必需事实全部明确时才启用:

  • 仓库链接需要真实 owner、repository 与 branch;
  • Giscus 需要仓库 / 分类名称和不可变 ID;
  • Google Analytics 需要项目自己的 measurement ID;
  • 反馈只有在分析存在时才记录结构化 gtag 事件;
  • 助手链接会把当前 URL 发送给第三方,因此必须做显式策略选择。

不完整的可选块应继续保持注释。各集成的运营边界见启用评论、 分析与 SEO和仓库与页面信息。

构建与部署

严格本地构建

启用托管 workflow 前执行:

hugo --cleanDestinationDir --gc --minify --environment production \
  --printPathWarnings --panicOnWarning

提交 hugo.yaml、go.mod 与 go.sum;不要提交生成的 public/、resources/、模块 缓存或本地模块替换。

GitHub Pages

Starter 已包含 .github/workflows/github-pages.yaml。在 Settings → Pages 中选择 GitHub Actions 作为 Source。推送到 main 后, workflow 使用固定工具链构建,向 GitHub 查询正确的项目子路径,再通过 Pages 部署 API 发布 public/。

Cloudflare Pages

内置 .github/workflows/cloudflare-pages.yaml 使用 Direct Upload。创建 Pages Direct Upload 项目,添加 CLOUDFLARE_ACCOUNT_ID 与 CLOUDFLARE_API_TOKEN,再手动 运行一次 workflow。设置仓库变量 CLOUDFLARE_PAGES_ENABLED=true 后才会自动部署; 规范地址不是默认 pages.dev 域名时,再设置 CLOUDFLARE_SITE_URL。

同一个项目只选 Direct Upload 或 Cloudflare Git integration 其中一种。完整托管对比 与 baseURL 规则见发布上线。

验证并删除示例

宣布站点完成前:

  1. 搜索 Project Name、example.org、OWNER、PROJECT 等占位符,逐项确认剩余位置 是否有意保留。
  2. 在桌面与移动端打开每种已启用语言的根,以及代表性的 Docs、Blog、Book 页面。
  3. 确认语言切换落到对页,而不是首页。
  4. 验证搜索、深色模式、一个组件、Markdown 输出、打印、404、canonical URL 与仓库操作。
  5. 把部署 workflow 和公开 URL 与本地构建分开检查。

删除示例 Book 或 Blog 之前,要同时移除对应顶部菜单根,以及首页上指向它的卡片。每整棵 删除一个内容区就严格重建一次,才能让失败归因到单一改动。

下一步

用 Starter 仓库导览查询文件职责,再继续阅读 编写页面与配置总览。已有站点不应 继承 Starter 内容模型时,改走从零建站路径。

2 - Starter 仓库导览

oink-starter 的文件级地图:身份、语言、首页、内容、导航、品牌、部署与固定主题分别由哪里管理。

本页说明从 pgsty/oink-starter 创建的仓库,不再介绍大得多的 oink.pgsty.com 文档与回归测试仓库。主题源码不会 复制进任何一个站点:go.mod 以 Hugo Module 形式固定版本,Hugo 把解析结果存进 Go 模块缓存。

顶层地图

oink-starter/

  • oink-starter/
    • hugo.yaml身份、语言、输出、参数与模块导入
    • go.mod站点模块与精确 OINK 版本
    • go.sum模块校验和
    • examples/
      • hugo.single.yaml仅英文的完整 profile
      • hugo.bilingual.yaml英文 + 中文的完整 profile
    • data/
      • home/
        • en.yaml每种语言一份精简落地页
        • zh.yaml
        • fr.yaml
    • content/
      • _index.md各语言首页根
      • _index.zh.md
      • _index.fr.md
      • docs/简介、快速上手、教程、参考
      • blog/文章、设计记录、发布说明
      • book/介绍 Starter 的连续教程
    • assets/
      • icons/logo.svg经 Hugo 处理的项目 Logo
    • static/
      • favicon.svg原样复制到站点根
    • i18n/
      • fr.yamlStarter 自有法语界面覆盖
    • .github/workflows/
      • github-pages.yaml严格构建与 GitHub Pages 部署
      • cloudflare-pages.yaml严格构建与 Cloudflare Direct Upload
    • README.md面向仓库维护者的操作摘要
    • LICENSE模板源码许可证

生成的 public/、resources/、.hugo_build.lock 与模块缓存是被忽略的构建状态, 不是源码。

最先修改什么

路径 职责 第一次操作
hugo.yaml 身份、规范 URL、语言、输出、主题功能、可选集成 修改两个标记值;其它修改前先选择语言 profile
data/home/ 首页承诺、卡片与行动入口 一种语言确认后,再重写所有已启用语言
content/ 全部读者可见内容 替换示例叶子;确认整个内容区不要时才删除栏目根
assets/icons/logo.svg 经处理的 Logo 有正式图形后再替换
static/favicon.svg 浏览器图标 与 Logo 一起评审后替换
hugo.yaml 中的 params.github_* 编辑、历史、新建页面与 issue 链接 目标仓库已存在后才取消注释

哪些必须保留

  • go.mod 与 go.sum:两者共同固定并校验模板选定的 OINK 版本,都要提交;这条基线与后续升级分开记录。
  • hugo.yaml 中三项 Goldmark 设置:原生 Steps、Cards、Fields、图片属性与 Book 目标都依赖它们。
  • outputs:删除 markdown、LLMS 或 print,会有意删除对应的 Markdown、 Agent 索引或打印内容区。
  • workflow 中的 fetch-depth: 0:保留 enableGitInfo 时,最后修改与贡献者事实需要 完整 Git 历史。
  • CI 中的 GOWORK: off 与 HUGO_MODULE_WORKSPACE: off:开发者本地 workspace 不得 替换 CI 正在验证的公开版本。

可选内容区

Docs、Blog 与 Book 是彼此独立的顶层内容区。安全删除其中一个的顺序是:

  1. 删除对应的 content/<surface>/ 内容树;
  2. 删除首页指向它的卡片或链接;
  3. 确认其它页面不再链接它;
  4. 严格构建,并检查剩余顶部导航。

不要只删除某种语言的栏目根:那会形成难以区分「有意不对称」与「漏译」的语言专属导航 和回退行为。要么在所有已启用语言中删除整个内容区,要么明确记录这种不对称。

完成语言选择后,examples/ 下两个配置 profile 可以删除,也可以作为参考保留;真正 生效的站点配置只有根目录 hugo.yaml。

内容与导航

Docs 与 Book 下的目录结构和 weight 共同形成侧栏与翻页顺序。顶部导航来自栏目根的 menus.main。译文根重复相同的 identifier、parent 与 weight,只翻译可见标签。

Starter 刻意演示 Documentation System 内容模型:

  • 简介回答是什么、为什么;
  • 快速上手帮助新用户得到结果;
  • 教程带领读者完成端到端任务;
  • 参考记录精确的受支持行为。

可以按项目需要改名或重组,但应保留不同学习路径之间的分工,不要把所有答案混进一棵树。

语言模型

英文源码以 .md 结尾,中文和法语对页分别以 .zh.md、.fr.md 结尾。首页数据按 data/home/ 下的语言键分文件。根 profile 声明语言、locale、顺序与站点描述。

单语与双语 profile 仍声明被禁用的语言,这是有意设计:Hugo 会把未使用后缀识别为 译文,而不会把多个文件渲染到同一个英文 URL。只在项目配置开始前复制 profile;之后 应手工合并。

OINK 在哪里

两个文件建立模块边界:

hugo.yaml
module:
  imports:
    - path: github.com/pgsty/oink
  hugoVersion:
    extended: true
    min: '0.160.1'
go.mod
module github.com/OWNER/PROJECT-DOCS

go 1.27.0

require github.com/pgsty/oink v1.0.0

这里展示教程采用的 Starter 快照 137843b,不是 OINK 最新版本;更新模板应以自己的 go.mod 为准。

hugo mod graph 显示实际解析版本。生产使用 go.mod 中的精确标签;本地 HUGO_MODULE_REPLACEMENTS 只是开发覆盖,绝不能提交,也不能当成发布证明。

部署文件

GitHub Pages workflow 在推送 main 后自动运行;仓库设置必须选择 GitHub Actions 作为 Pages Source。Cloudflare workflow 默认手动运行,只有仓库变量 CLOUDFLARE_PAGES_ENABLED=true 存在时才自动执行;所需账号 ID 与 API token 始终 保存在仓库 secrets 中。

只保留实际运营的部署路径。Cloudflare Direct Upload 与 Cloudflare Git integration 是同一个项目的两种所有权模型,不是应当同时运行的两道关卡。

安全的定制顺序

  1. 证明未修改的预览可用。
  2. 先选择语言,再修改身份。
  3. 替换一种首页,再补齐译文。
  4. 替换内容并验证导航。
  5. 品牌与阅读功能一次只改一组。
  6. 启用完整的外部集成。
  7. 执行严格生产构建。
  8. 部署,再独立验证生产环境。

仓库已经属于自己后,每层之间做一次提交。小边界能让后续回归与回滚明确归因到一个决定。

验证

hugo mod graph | grep github.com/pgsty/oink
hugo --cleanDestinationDir --gc --minify --environment production \
  --printPathWarnings --panicOnWarning
git status --short

模块图应显示固定发布,构建没有警告或错误,Git 状态只包含源码修改而没有 public/ 或 缓存。之后打开所有已启用语言的根,以及代表性的 Docs、Blog、Book 路由,再进入部署。

3 - 从零建站与其它安装方式

从空目录搭一个最小 OINK 站点,以及 Module / submodule / 离线归档 / 固定版本源码副本四种安装方式的取舍。

这是推荐路径 OINK Starter 的手工替代方案。本页从空目录 搭建一个最小 OINK 站点:一份精简 hugo.yml 加一条 hugo mod get,得到一个可预览 的单语站点。代价是首页、示例内容、部署 workflow 与每种组件用法都要自己组装。

已有 Hugo 站点时,按下方接入现有站点操作;已有 Docsy 站点见版本升级。

后半部分是四种安装方式的取舍:Hugo Module、Git submodule、离线归档、固定版本源码副本。 OINK 1.1.0 使用 Go 1.27 与 Hugo Extended 0.165.0 做发布验证。 主题声明的较低兼容下限用于刻意保留旧工具链的既有站点。

接入现有站点

在保留现有配置与内容的分支中操作。跳过 hugo new site,继续使用原配置文件名。

  1. 只有站点没有 go.mod 时,才用自己的仓库模块路径执行 hugo mod init;已有模块声明保持不变。
  2. 执行 hugo mod get github.com/pgsty/[email protected]。
  3. 用下方的 OINK module.imports 替换旧主题引用,保留无关导入与配置。合并示例中的三项 markup.goldmark 设置与 markup.highlight.noClasses: false,不要整份覆盖原配置。
  4. 检查站点自有 layouts/、资源、旧主题短代码,以及页面的 type/layout:这些覆盖和约定可能仍然选择旧主题行为。保留内容,只做必要适配。
  5. 执行 hugo --panicOnWarning,再用 hugo server 打开一篇已有的代表性页面。先核对导航、图片与代码块,再启用可选 OINK 功能。最后按验证完成检查。

从空目录到第一页

  1. 建骨架并获取主题

    hugo new site --format yaml my-docs
    cd my-docs
    git init
    hugo mod init github.com/example/my-docs
    hugo mod get github.com/pgsty/[email protected]

    hugo mod init 后面跟的是你自己站点的模块路径,通常就是仓库地址。hugo mod get 会写出 go.mod 与 go.sum,两个都要提交。

    构建前创建 .gitignore,避免把生成文件加入 Git。完成首个提交前,保持 enableGitInfo 关闭:

    .gitignore
    /public/
    /resources/
    /.hugo_build.lock
    /.hugo_cache/

    最新版本号在 GitHub Releases;本页出现的 v1.2.0 是本站当前固定的版本。生产站点固定到发布标签,不要跟随 main:@latest 是一次性解析动作,不是版本策略。

  2. 写 hugo.yml

    仅对这个新站:把生成的 hugo.yaml 改名为 hugo.yml(Hugo 两者都接受),再用下面内容替换。已有站点应合并所需配置,不要整份覆盖:

    hugo.yml
    title: Product Docs
    baseURL: https://docs.example.com/
    defaultContentLanguage: en
    # enableGitInfo: true        # 页面「最后修改」时间来自 git,完成首次 Git 提交后再打开
    
    languages:
      en:
        label: English
        locale: en-US
        weight: 1
        title: Product Docs
        params:
          description: Everything about running Product in production
        menus:
          main:
            - { name: Docs, pageRef: /docs, weight: 20 }
            - { name: Blog, pageRef: /blog, weight: 50 }
    
    # 三项 Goldmark 前置:OINK 的原生 Markdown 组件全靠它们
    markup:
      goldmark:
        renderer:
          unsafe: true # 允许内容里的行内 HTML
        parser:
          attribute:
            block: true # {.steps} {.cards} {caption=} 这类属性行
          wrapStandAloneImageWithinParagraph: false # 块级图片才能带属性行
      highlight:
        noClasses: false # 代码配色跟随深浅色模式
    
    params:
      offline_search: true
      github_repo: https://github.com/example/product-docs
      copyright:
        authors: '[Example Inc.](https://example.com/)'
        from_year: 2026
      ui:
        dark_mode: true
        sidebar_menu_foldable: true
        section_index: cards
    
    outputs:
      home: [HTML, markdown, LLMS]
      page: [HTML, markdown]
      section: [HTML, RSS, print, markdown]
    
    module:
      imports:
        - path: github.com/pgsty/oink
      hugoVersion:
        extended: true
        min: '0.160.1'

    五段分别管什么:

    段 管什么 少了会怎样
    顶层 + languages 站名、域名、语言与顶栏菜单 baseURL 不对,线上所有绝对链接指错
    markup.goldmark 三项组件前置 属性行变成正文里的一行 {.steps}
    params 搜索、仓库链接、外壳开关 交互功能默认关闭,主题不替站点决定
    outputs 每页的 .md、llms.txt、打印页 页面菜单里没有「复制 Markdown」,也没有打印视图
    module 引用主题、声明 Hugo 下限 构建时找不到主题

    写公式还需要 Goldmark 的 passthrough 扩展,见公式。每个键的完整含义与默认值见配置总览。

  3. 写第一页

    content/ 下的每个一级目录是一个分区,目录结构就是侧栏结构。文档分区至少要有一个 _index.md:

    content/docs/_index.md
    ---
    title: Docs
    linkTitle: Docs
    description: Everything about running Product in production.
    weight: 20
    ---
    
    从[安装](/docs/install/)开始。
    content/docs/install.md
    ---
    title: Install
    description: Install Product on a fresh machine.
    weight: 10
    ---
    
    ## Prerequisites {#prerequisites}
    
    > [!IMPORTANT]
    > Product 需要 PostgreSQL 18 或更高版本。
    
    ## Install {#install}
    
    ```bash
    curl -fsSL https://get.example.com | bash
    ```

    标题写显式 {#id}:后续加译文时两种语言的锚点才能对应。页面写法见编写页面。

  4. 预览

    hugo server

    打开 http://localhost:1313/docs/,Docs 分区中应列出 Install。添加首页内容之前,根地址的首页仍为空。修改 Install 页面,确认预览随之更新。

其它安装方式

上面用的是 Hugo Module。另外三种方式面向特定约束:网络隔离、平台要求构建输入包含完整主题树、组织内部需要评审主题副本。除 hugo mod vendor 之外,它们都不建立 Go 模块,站点用 theme: oink 而不是 module.imports 引用主题;共同的代价是版本解析与完整性校验由你自己负责。

Hugo Module(推荐)

hugo mod init github.com/example/product-docs
hugo mod get github.com/pgsty/[email protected]
hugo.yml
module:
  imports:
    - path: github.com/pgsty/oink

唯一能让 Hugo 自己解析版本、校验 checksum、并在 go.sum 里留下审计记录的方式。hugo mod graph 看实际解析结果,hugo mod get -u 升级。需要本机有 Go。

Git submodule

在站点仓库里记录准确的主题 commit:

git submodule add https://github.com/pgsty/oink.git themes/oink
git -C themes/oink fetch --tags
git -C themes/oink checkout v1.2.0
git add .gitmodules themes/oink
hugo.yml
theme: oink

CI 必须在运行 Hugo 之前初始化 submodule,否则 themes/oink 是空目录:

git submodule update --init --recursive

离线归档

网络隔离环境使用。两条路径,都先在联网机器上准备,再整体搬入。

用 hugo mod vendor:把已解析的主题源码固化进站点目录,之后构建既不联网也不需要 Go。

hugo mod vendor          # 生成 _vendor/,里面是主题的完整源码树
tar czf ../my-docs.tgz . # 把归档写到正在打包的目录之外

_vendor/ 存在时 Hugo 优先使用它(hugo mod graph 输出 +vendor),hugo.yml 里的 module.imports 保持不变。这一步需要 Go,之后的构建不需要。升级主题要回到联网环境重新执行 hugo mod get 与 hugo mod vendor。

_vendor/ 只收主题挂载出来的目录(assets data i18n layouts static)以及 hugo.yaml 与 theme.toml,不含 LICENSE、NOTICE 与 VENDOR.json。要对外分发这份归档,把这三个文件从主题仓库一并取来。

用 tag 源码归档:不建 Go 模块,直接把某个版本的主题解压到 themes/oink/。

curl -L -o oink.tar.gz \
  https://github.com/pgsty/oink/archive/refs/tags/v1.2.0.tar.gz
mkdir -p themes/oink
tar xzf oink.tar.gz -C themes/oink --strip-components=1
hugo.yml
theme: oink

主题仓库的根目录就是模块根目录,解压出来直接是 layouts/、assets/、i18n/、static/ 这一层,不需要再进入下一级。重新分发时必须保留 LICENSE、NOTICE 与 VENDOR.json。最后一个记录了每个第三方运行时的版本、来源、许可证路径与 SHA-256,是离线审计的依据。

跨机器传输时,在联网侧从不可变标签生成归档与校验值:

git clone --branch v1.2.0 --depth 1 \
  https://github.com/pgsty/oink.git oink
git -C oink archive --format=tar.gz --prefix=oink/ \
  --output=../oink-v1.2.0.tar.gz v1.2.0
shasum -a 256 oink-v1.2.0.tar.gz \
  > oink-v1.2.0.tar.gz.sha256

把归档与 .sha256 一起传入隔离环境,先校验再解压:

shasum -a 256 -c oink-v1.2.0.tar.gz.sha256
mkdir -p themes
tar -xzf oink-v1.2.0.tar.gz -C themes

这样得到的归档是自建产物,不是项目发行物。某个标签的发行页面是否附带归档与校验文件按发布而定,使用公开附件时独立验证其校验值。

断网构建之前确认归档内容完整,这十一项都要在:

themes/oink/

  • oink/
    • go.mod模块路径声明,Hugo Module 方式解析用
    • hugo.yaml主题默认参数与 Hugo 版本下限
    • theme.toml主题元数据,theme: oink 方式需要
    • LICENSEApache-2.0
    • NOTICE上游署名,再分发时必须保留
    • VENDOR.json第三方运行时清单:版本、来源、许可证路径、SHA-256
    • assets/SCSS、JS 与随主题分发的第三方运行时
    • layouts/模板、partial、shortcode、render hook
    • static/字体文件,原样发布
    • i18n/32 份界面语言文件
    • data/页尾出处行用的 SPDX 许可证表

固定版本源码副本

托管平台要求站点仓库包含主题文件时,按上方tag 归档步骤准备并解压到 themes/oink/。配置 theme: oink,把解压后的文件连同已验证的标签与校验值记录一起提交。

直接 git clone ... themes/oink 会保留嵌套 .git 目录,加入父仓库时记录的是 Git 引用, 而非主题文件,因此不能得到这里所需的完整源码副本。希望用 Git 引用跟踪主题时,应使用 submodule。

四种方式对比

方式 需要 Go 版本可审计 主题源码进你的仓库 适用
Hugo Module 是 go.sum 自动校验 否 默认推荐
Git submodule 否 仓库记录 commit 以引用形式 需要主题源码在库内
离线归档 否 手工核对 checksum 是 网络隔离
固定版本源码副本 否 记录标签与校验值 是 平台要求完整树
消费站点不需要前端工具链

Bootstrap、Font Awesome、字体、搜索与图表运行时全部随主题分发。站点不需要 node_modules、PostCSS、RTLCSS,也不需要 CDN。为 Docsy 站点安装 npm 依赖的教程属于上游 Docsy 的流程,不适用于 OINK。

用本地主题 checkout 开发

同时修改主题与站点时才需要这一节。把两个仓库克隆为同级目录:

同级目录布局
~/pgsty/
├── oink/            # 主题
└── product-docs/    # 你的站点

用环境变量 HUGO_MODULE_REPLACEMENTS 把模块临时替换为本地 checkout,go.mod 不变:

cd ~/pgsty/product-docs
HUGO_MODULE_REPLACEMENTS='github.com/pgsty/oink -> ../oink' hugo server

文档站仓库的 Makefile 就是这几条命令的别名,make dev 与 make check 要求主题 checkout 在同级目录 ../oink:

Makefile:文档站里的写法
build:
	hugo --cleanDestinationDir --minify

check:
	HUGO_MODULE_REPLACEMENTS='github.com/pgsty/oink -> $(abspath ../oink)' npm test

dev:
	HUGO_MODULE_REPLACEMENTS='github.com/pgsty/oink -> $(abspath ../oink)' hugo server --renderToMemory

Go workspace(go work init + HUGO_MODULE_WORKSPACE=go.work)是等价的另一种做法。两种做法都只作用于本机:CI 与生产构建用的是 go.mod 里的版本,go.work 不要提交。

验证

hugo mod graph                                       # 主题实际解析到哪一版
hugo --gc --minify --printPathWarnings --panicOnWarning

构建以 Total in … 结束、没有 WARN / ERROR 即通过。再确认:

  • /docs/ 打得开,侧栏里有你写的页面
  • 顶栏有搜索框,搜得到刚写的标题
  • 深浅色切换按钮在,切换后代码块配色跟着变(说明 markup.highlight.noClasses: false 生效)
  • git status --short 只列出源码修改,生成产物已被忽略。Module 方式提交 go.mod 与 go.sum;其它安装方式保留各自的主题源码或 submodule 记录。

4 - OINK CLI 功能与后续方向

2026-09-30 的六命令 CLI 快照、安全与自动化能力,以及当时提出的后续研发方向。
首期历史快照

本页保留 2026-09-30 的命令清单与证据。六个命令、平台状态及 CI 建议描述的是 当时情况。当前维护行为归CLI 契约与 使用指南所有; 维护记录 保留其指定源码与二进制的历史验收。 本地验收不代表公开 CLI 发布或部署。

oink 是面向 OINK 站点维护者的命令行工具,把创建站点、检查环境、验证产物、 本地预览和主题升级放在同一个入口中。当前六个命令已经形成可用的本地工作流程。 接下来最有价值的工作,是让更多用户能顺利安装、准确定位问题并重复完成维护; 迁移、文档版本管理和 API 参考生成可以在此基础上逐项推进。

本文介绍现有功能和后续方向。完整安装步骤见使用 OINK CLI, 已执行的测试见首期验收记录。

当前状态

截至 2026-09-30,本文对应本地 0.1.0-dev、提交 e623d93。代码、测试、 安装流程和可复现归档已经准备并验证;公开 CLI 发布和部署尚未完成。 下文的后续功能是建议或既有提案,不是可立即使用的命令,也不构成排期承诺。

工具的定位

OINK 主题负责页面呈现、导航、搜索、内容组件和各类输出,Hugo 负责配置加载和渲染。 CLI 负责把这些输入与结果串成可检查、可重复的维护流程:哪里配置不对、实际用了哪份 主题、链接是否失效、升级会修改什么,都应有可查看的证据。

CLI 是独立的 Go 可执行文件,调用外部 Hugo,不依赖 Python、Node.js、账户或后台服务。 初始化后的站点保留普通 Hugo 配置与内容;依赖齐备后,即使不安装 CLI,也能直接用 Hugo 构建。主题和 CLI 的版本号承担不同职责。

它适合三类使用者:新站维护者可以更快建立基线;既有站点维护者可以诊断、检查和 审阅升级;CI 或自动化程序可以读取稳定的 JSON 结果与退出码。

已实现的六个命令

命令 解决的问题 当前行为与边界
oink doctor 环境能否工作,站点实际用了什么 检查 Hugo Extended 与版本、必要的 Go/Git、生效配置、主题固定版本与实际来源,以及 workspace、replacement、vendor、语言和输出。只读诊断,不构建站点。
oink check 构建后是否存在可检测的问题 复制输入并隔离输出和缓存,用 --panicOnWarning 构建,再检查实际产物中的站内链接、锚点、资源及受支持的机器输出。
oink init <目录> 如何得到可用且可复现的起点 从内嵌、保留许可证与来源记录的固定 Starter 快照生成站点。支持 en、en,zh、all(英中法);候选验证通过后才创建文件,拒绝覆盖非空目录。
oink upgrade --to <标签> 升级是否可行,会改动什么 只处理选定的一个站点,先验证候选,再输出计划。默认不写入;显式 --write 才应用选定的模块文件变更。
oink dev 如何启动日常本地预览 透明调用 hugo server,-- 后的参数传给 Hugo,并转发进程信号。
oink build 如何执行严格的生产构建 透明调用 Hugo,默认选择 production,加上 --panicOnWarning。不会额外执行 check 的引用检查。

doctor 和 check 的区别在于是否真正构建并检查产物。build 生成站点通常使用的 发布产物,check 则在隔离副本中验收。dev、build 可以写入正常的 Hugo 输出和 缓存;只读诊断与升级预览保留站点源码。

检查以实际产物为准

check 由 Hugo 枚举各语言、各页面实际声明的输出格式和 URL,再核对生成文件。 它支持多语言、根路径与子路径,尊重 URL 编码和外部链接边界,不从 Markdown 文件名 自行推导另一套路由。页面输出覆盖、未进入列表的静态页面,以及有意只生成链接而 不渲染的页面,都按 Hugo 的实际语义处理。

受支持的机器输出包括 NAVJSON v1 导航树、BookManifest v1 书籍清单、离线搜索索引、 LLMS 导览和 LLMSFULL 内容集合。未启用的输出不是错误;某个语言应有但缺失的输出 不能被另一种语言的有效文件掩盖。未知且必需的契约会报告未完成覆盖。

check --release 验证面向公开主题版本的构建:关闭 Go 与 Hugo 两套 workspace, 并禁用隔离副本中的 Hugo replacement。冲突的主题 go.mod replace 会被报告, 不会被静默删除。实际选中 vendor 时,普通 check 可以检查产物;--release 则会 指出公开来源的字节验证尚未完成。

升级前先验证候选

升级计划说明目标版本、待改文件和前后状态。写入可以通过 --expect-plan 绑定已审阅 的计划,还会检查目标文件是否在计划后变化。未提交的目标模块文件受到保护,无关依赖 和用户修改保留,写入失败时提供备份与恢复证据。遇到并发编辑,恢复不能为了撤销 自己的操作而覆盖用户的新内容。

目前升级处理 go.mod 与 go.sum,不自动刷新 _vendor,也不改写任意内容或配置。 vendor 刷新需要单独、显式且可审阅的流程。CLI 不执行 commit、push 或部署。

自动化与离线能力

所有命令都不等待交互。--json 的 stdout 只输出一份 oink.result/v1,工具日志写入 stderr。结果包含规则 ID、严重度、已知位置、解释、行动建议、覆盖状态和 Hugo 原始 证据;无法确定源码行号时,不编造位置。

退出码 含义 自动化应如何理解
0 必需工作完成,没有阻断项 本次请求通过;仍要查看未执行的覆盖项。
1 已完成的检查发现政策问题 根据诊断修改输入,再次检查。
2 必需工作未完成 排查工具、构建、I/O、缓存或不支持的输入;不能视为检查通过。

默认使用离线策略,只有显式 --network 才允许本次操作联网。CLI 不下载 Go 工具链、 安装系统包、修改全局配置或增加遥测。模块依赖预备齐全后,受支持的流程可以离线运行; 缓存不足会准确失败。

隔离命令使用可清理的临时缓存,init --network 成功不等于后续命令已有持久缓存。 当前只复用已准备的模块下载制品,不复用 Hugo 全局远程资源缓存。构建时必需的远程 内容应预先保存为本地资源,或为该次调用明确启用网络。

一条完整的使用路径

完成本地安装,并安装 Starter 所需的 Go、Git 和 Hugo Extended 后,可以按下面的顺序工作。首条命令是显式的联网依赖预备步骤:

GOWORK=off GOTOOLCHAIN=local go mod download github.com/pgsty/[email protected]
export GOMODCACHE="$(go env GOMODCACHE)"

oink init my-docs --languages en,zh
oink doctor --site my-docs
oink dev --site my-docs -- --bind 127.0.0.1 --port 1313

预览时修改站名、baseURL 和内容,结束预览后执行:

oink check --site my-docs --release --json > check.json 2> check.log
oink build --site my-docs -- --minify

升级既有站点时先预览,再按升级指南审阅计划并显式写入。 这里的 OINK v1.1.0 是已验收的初始化基线,不表示它始终是最新主题版本。

已验证范围与当前限制

首期验收记录覆盖 Go 测试、vet、race、三种 Starter 配置的普通 Hugo 根路径与子路径 构建,以及 OINK 文档站、PIG 站点和软件仓库文档站三个真实消费站。还执行了操作系统 禁止联网条件下的初始化与检查、真实升级写入保护、薄包装进程和归档复现检查。

实际运行平台为 macOS arm64,记录的工具链为 Go 1.27.1、Hugo Extended 0.166.0。 Darwin amd64 与 Linux amd64/arm64 已交叉编译,尚未完成对应平台的运行验收; Windows 不属于首期支持范围。源码安装可用,公开下载、标签安装和 Homebrew 分发 尚未交付。

当前隔离检查支持已物化、单主机的站点。关联 Git worktree 的 .git 指针、已挂载 符号链接、隔离范围之外的挂载、自定义配置目录、动态内容适配器、多主机语言输出, 以及抑制验证探针的 render segment,仍有明确的支持边界,详见 输入范围表。不支持的必需输入不会得到完整检查通过的结论。

静态检查不证明浏览器交互、无障碍、外链可访问性、托管重定向、翻译完整性或内容语义 正确。浏览器验收与部署验收应由相应流程负责。

下一步优先完善的功能

建议先围绕现有六个命令减少使用阻力。下面是基于首期限制的功能建议,尚未实现; 涉及新参数或新契约时,仍应进入正式提案流程。

优先方向 可以增加的能力 完成时应看到的结果
安装分发与平台支持 在目标 macOS/Linux 平台运行完整流程,发布带校验和的正式归档,提供可复现的标签安装或 Homebrew 入口。 新用户按公开说明即可安装、初始化、预览并检查,平台声明都有实际运行证据。
更易行动的诊断 按工具、依赖、配置、产物分组;增加规则说明和修复示例;只在有可靠映射时回溯源码位置;评估 CI 注解或 SARIF 导出。 用户能定位应修改的输入,CI 保留原始证据,误报能用真实样本复核。
明确的依赖预备 提供显式缓存预备与缺项报告,区分模块和远程资源,记录确切版本、来源及网络需求。 第一次联网准备后能够重复离线运行;失败时能说清楚缺什么、如何准备。
更完整的升级维护 评估单独的 vendor 候选刷新与字节比对、可保存的审阅计划及更直接的恢复说明。 用户能审阅完整差异;vendor、无关依赖与并发修改继续受到保护。
更顺手的初始化与创作 提供站名、URL 和受支持语言配置的声明式输入;增加少量官方文档、文章和 Book 页面模板。 减少手工改占位内容的步骤,生成的仍是普通 Markdown、data 和 Hugo 配置。
扩大真实项目覆盖 优先验证关联 worktree 等常见结构,再按需求处理多主机、外部挂载和动态内容;依据测量优化大站检查耗时。 每新增一种支持范围,都有不改源文件、失败可解释的回归证据。

不建议同时启动所有方向。先用独立用户的安装和维护记录找出最常见的阻碍,每次选择 一个可验证的改进。新的忽略规则或检查基线不能掩盖 Hugo 构建失败或必需覆盖缺失。

随后可以扩展的产品能力

以下方向已在CLI 路线图讨论,仍是 后续提案。它们应继续遵守“生成普通站点源码,渲染不依赖 CLI”的边界。

能力 CLI 可以承担什么 主要前提与限制
有范围的 Docsy 迁移 先生成评估报告,逐项标注兼容、可转换、需人工复核或不支持;随后向新目录转换并核对旧新路由。 先支持真实样本中的一套明确配置,不承诺任意 Docsy、MDX 或 React 内容的一键迁移;原始文件和代码示例必须保留。
文档版本生命周期 准备版本快照、维护小型版本清单、检查跨版本页面对应关系和归档状态。 主题负责读者界面,CLI 生成可纳入 Git 的配置;缺页不能伪装成等价页,各版本仍可独立构建。
静态 OpenAPI 参考 从本地规范生成操作、参数、请求响应和 Schema 的 Markdown/data,让既有 Hugo 输出链路处理它们。 先定义规范子集,保证可重复生成并保护人工修改;远程引用显式准备,请求执行、凭据管理和 SDK 平台另行考虑。
Agent 与编辑器集成 在稳定 JSON 结果之上评估编辑器入口或 MCP,让其他工具复用相同诊断和升级计划。 先证明现有命令被反复使用;MCP、Studio、图谱和托管服务都需要独立需求与维护资源。

推荐顺序是先完成可公开使用的维护工具,再以评估报告启动首条迁移路径。新增内容 能力默认优先文档版本生命周期;若真实 API 用户有更强的重复需求,再将静态 OpenAPI 提前。同一阶段选择一个基础能力,避免同时维护多套尚未经过用户验证的模型。

进一步阅读

5 - 使用 OINK CLI

在本地构建可选的 Go 命令行工具,初始化固定 Starter、检查既有站点,并在写入前验证单站点主题升级。

oink 是 Hugo 的可选 Go 命令行工具。当前本地 0.1.0-dev 候选专注于诊断、 真实产物检查、初始化、构建、主题升级与有保护的维护计划。Hugo 继续负责渲染, 站点可以使用普通 Hugo 构建。

本地实现

本指南描述 2026-10-04 的收缩命令界面。CLI 尚未公开发布或分发;旧 R1–R8 验收属于对应历史源码与二进制。当前范围由CLI 契约 定义,Studio、通用编辑、context、snippets、editor 与 CI 生成已撤下。

当前缓存模块移动流程的集成验证首次失败、单用例重跑通过,间歇失败尚待调查。详见 验证限制。

本地构建与安装

在已有的 oink-cli 源码 checkout 中,使用 Go 1.26 或更新版本及 Make:

make deps                    # 显式联网预备 Go 依赖
make build                   # 使用本地工具链,离线构建到 bin/oink
./bin/oink --version
./bin/oink --help
make install                 # 默认安装到 $HOME/.local/bin
export PATH="$HOME/.local/bin:$PATH"

export 只影响当前 shell。CLI 不安装系统工具,也不修改 shell 配置文件。 make install PREFIX=/你的前缀 可选择其他前缀,BINDIR=/你的目录 可指定准确目录。 源码构建需要 go.sum 中的依赖;make deps 在有网络时显式预备这些依赖。 之后的构建与安装目标使用本地工具链,不下载依赖或其他 Go 编译器。

带日期的运行时验收记录 对其绑定的历史候选实测 macOS arm64、原生 Linux arm64 和通过 QEMU TCG 模拟的 Linux amd64,使用 Go 1.27.1、Hugo Extended 0.166.0 与公开 OINK v1.1.0 模块。Hugo 版本检查接受 Extended 0.160.1 或更新版本,但这不代表 每个被接受的版本都经过测试。内嵌 Starter 的文档要求 Hugo Extended 0.165.0 或更新版本,以及 Go 1.27。当时的 Linux 测试在 ext4 上以非 root 用户运行,使用 已供应离线依赖,实际执行必需文件系统/信号与选定实际 Hugo 案例。guest 缺少 的可选工具保持明确跳过,拥有独立 host 协议证据。两个新构建复现全部五份归档, 三个声明运行归档在 checkout 外提取/执行,无 Node 依赖。Darwin amd64 为实验 归档,实际 Bad CPU type 后仍未验证;交叉编译不证明运行支持。Windows 不在声明范围。 这些结果只适用于记录绑定的源码与归档,不能自动证明后续收缩后的 CLI 或新构建的可执行文件。

make release VERSION=0.1.0-dev DIST=dist 在新目录或空目录中准备四份二进制 归档、一份源码归档及 SHA256SUMS,不会公开发布。已验证平台与可复现性边界见 归档验收与复现步骤。

从固定 Starter 创建站点

如果尚未缓存公开主题,先预备一次。下面是显式的依赖预备命令,可能访问网络:

GOWORK=off GOTOOLCHAIN=local go mod download github.com/pgsty/[email protected]
export GOMODCACHE="$(go env GOMODCACHE)"
oink init my-docs --profile docs --languages en,zh

init 接受新目录或已有空目录,父目录必须存在。它拒绝包含既有文件的目标 (包括隐藏文件),也拒绝以符号链接作为目标。创建任何目标文件之前,它会先验证临时 候选站点,并检测操作期间目标发生的变化。

选择 --profile project(默认)、docs、blog 或 book。project 保留此前 完整 Starter 投影;其他配置保留对应归档内容分区,并将已有本地化站名、首页卡片/ 动作和导航投影到该分区。选定内容及共享资源/示例/工作流/许可证保留归档字节, 生成配置与首页 YAML 是唯一序列化的配置投影。归档工作流示例不变,不是 ci init 的校验和绑定 CI 计划。

语言仍独立选择 en(默认)、en,zh、all(英语、中文、法语)。全部配置使用同一 份内嵌 MIT 许可证 Starter 提交 137843b25bacd76ddd1f7ce71330bf2e3155b954, 按记录的 Go 校验和固定 OINK v1.1.0,并在首次 Git 提交前关闭 enableGitInfo。 不在运行时抓取模板、初始化 Git 或提交。未知配置在写入前失败,必需 Hugo 缺失或 验证失败保留新建/空目标。

修改 my-docs/hugo.yaml 中的站名与 baseURL,再按 Starter 教程修改首页数据和示例内容。自行创建 Git 历史后, 可以按需启用 enableGitInfo。生成站点无需 CLI,普通 Hugo 即可构建:

cd my-docs
GOWORK=off HUGO_MODULE_WORKSPACE=off GOPROXY=off HUGO_MODULE_PROXY=off \
  GOTOOLCHAIN=local hugo --environment production --panicOnWarning
cd ..

这里使用上文导出的 GOMODCACHE 与预备依赖。全部 12 种配置/语言组合均以普通 Hugo 的严格模式通过根 URL 与 /manual/ 构建,共 24 次。产物本地引用已检查, 完整源码字节/模式/文件清单前后精确相等。公共 init/check 测试另覆盖四种配置的 英语和双语选择、默认 project 字节/模式一致,以及失败路径。

创建普通内容

从上文初始化的双语站点开始。预览新页面包和中文草稿,检查 diff 与候选结果, 再应用保存的计划:

oink new content/docs/guide --site ./my-docs --title "Getting started" --translations zh --kind docs --plan new-guide.json
oink plans apply new-guide.json --site ./my-docs

--language 默认采用生效默认语言,--kind 默认为 page,也支持 docs、blog、 book。站点相对包路径必须通过实际内容挂载及语言站点矩阵得到明确映射。语言 目录保留不同物理索引,共享文件名采用实际语言关系。已有包或占用同一页面 的同级文件被保留。主文件是普通页面,选定译文是以输入标题为占位内容的草稿。 只有显式人工审阅后才有审阅状态。每份新文件须由实际 Hugo 识别为一个具有实际 渲染输出的站点自有页面;仅链接/无输出、忽略或 build-never 新文件不能仅凭既有 内容构建正常而通过。保存计划 不写对应站点文件,应用重新核对绑定的新目录/源码状态,失败时保留后续编辑器附件。

编辑器设置与片段由普通编辑器管理,CLI 不再生成这些配置。

检查页面与已提交变更影响

使用实际页面 ID、Hugo Path、permalink 或捕获的源文件路径。language:path ID 可避免多语言选择歧义:

oink inspect 'en:/docs/old' --site my-docs --offline --json
oink impact --since HEAD --site my-docs --offline --json
oink check links --since HEAD --site my-docs --offline --json

从实际捕获页面事实中选择 ID;示例页面需要在你的站点中存在。inspect 展示观察到 的引用、实际输出、翻译同伴与物理 bundle 输入。impact 渲染选定 Git 已提交树及 当前站点,纳入已删除的旧身份和未修改的入站页面。全局配置、模板、数据或不确定 归属的变更扩大范围。观察到无法证明页面归属的 alias 输出时也扩大为全范围,不按 front matter 猜测归属。

check --since 当前执行完整当前检查。分别阅读 data.check_scope: full 与 描述因果范围的 data.impact.full_scope。完成的 inspect/impact 事实查询返回 0, 质量发现保留在 data.current_check;完整检查仍按政策返回发现 1。历史缺失或 不能渲染为必需未完成 2:已知当前事实继续可见,旧身份与变更保持未知。不会借用 当前外部本地依赖作为历史字节。支持已提交的站点内部主题;符号链接、submodule、 必需历史不受支持或不完整均明确声明。

预览并应用内容移动

oink move content/docs/old content/docs/new --site my-docs --offline \
  --plan /tmp/oink-move-plan.json --json
oink plans apply /tmp/oink-move-plan.json --site my-docs --offline --json

使用干净的物理站点相对文件/bundle 路径,将新计划保存在选定站点之外。预览展示 原始检查、临时路由探测、最终验证、翻译/附件映射、字节/完整模式 diff、实际新旧 路由、alias 建议与人工引用。临时探测可能产生旧链接发现 1;只有最终候选能验证 计划。不重写原始 HTML、shortcode 输出、变换或歧义目标。它们的最终断链返回 1, 不保存计划。重复的普通 Markdown 目标若无法证明精确源码/输出出现位置归属,也 保持人工处理,包括聚合/打印输出。在编辑器中审阅人工源码位置与实际输出 pointer, 再创建新预览。附件移动需要证明新的发布 URL,不能只依据新物理路径。配对且字节 相同的处理后图片输出可被证明,而绝对原始资源 URL 仍可能人工处理;不自动构造 这些未证明 URL。alias 仅供审阅,不自动序列化 front matter。

显式应用已保存计划前重新捕获并生成实际证明,再写选定文件。完整源码哈希、模式、 清单、外部输入与新目标目录持续受保护。已有目标、后续源码/附件/配置编辑或模式 变化返回 2,不覆盖这些改动。移动保留原始模式、二进制字节、无关文件与 Git index,不提交。所得普通 Hugo 输入可脱离 CLI 继续构建。若应用在写入期间失败, 检查报告中命名的恢复目录。

诊断并验证既有站点

可以在任意目录运行,并明确选择一个站点:

oink doctor --site ./my-docs
oink check --site ./my-docs
oink check links --site ./my-docs --format json
oink check --site ./my-docs --base-url https://example.org/manual/
oink check --site ./my-docs --release --keep-work

doctor 报告实际 Hugo 可执行文件与版本、所需工具、声明的主题 pin、生效 Hugo 配置、模块图与挂载、workspace、replacement、vendor 状态、语言及启用输出。 它不会构建站点。调查 Hugo 错误时,应将原始子进程证据与结构化发现一并保留。

check 将输入复制到临时目录,隔离构建产物与缓存,以 --panicOnWarning 运行 Hugo,再根据渲染文件检查受支持的站内链接、锚点、资源与机器输出引用。每种语言下 每个页面实际启用的输出格式与 URL 都由 Hugo 枚举,包括 front matter 覆盖和未进入 普通页面列表的静态页面。临时验证输出仅加入隔离副本,并在产物检查前移除。CLI 不根据 Markdown 文件名推导路由。未启用的机器输出不构成错误。覆盖条目说明哪些检查 已完成、未执行、不支持或未完成。浏览器交互、无障碍、外部 URL 可访问性、服务端 重定向与部署不属于静态检查范围。

JSON 的 data.pages 提供 Hugo 页面身份、实际路由、别名、语言、翻译、发布设置、 已知来源及输出;data.references 提供观察到的产物引用和已检查的锚点状态。 没有可靠文件来源的生成页面明确保留未知状态。这些是生产视图事实; 其存在不证明未声明的翻译覆盖,也不会虚构 Markdown 源码行号。 人类可读输出汇总页面/引用数量;完整数组请使用 JSON。

这两个命令都会保留源文件。--keep-work 保留临时目录并报告路径,便于检查;未指定 时会删除临时目录。站点需要特定配置、环境或 Hugo 可执行文件时,可使用 --config FILE、--environment NAME 和 --hugo PATH。配置文件必须位于 选定站点内部。诊断时,--environment 优先于 HUGO_ENVIRONMENT;均未指定时 使用 production 环境。如果 Hugo 在临时副本中添加或修改 go.mod、go.sum, CLI 会报告依赖预备尚未审阅,不会把修改应用到源码,也不将原始输入静默报告为就绪。

--release 关闭 Go 与 Hugo 两套 workspace,并在隔离副本中禁用环境变量及 Hugo 配置中的 replacement,但保留 go.mod replacement。在声称完成公开 pin 检查前,必须明确 处理本地 OINK replacement;CLI 不会静默删除它。vendor 证据也独立存在: go.mod 中声明了公开版本,不代表 _vendor 中的实际字节与该版本一致。

首期隔离检查具有以下范围限制:

输入形态 当前行为
自带 .git 目录的普通 checkout,或不含 Git 的实际文件副本 在其他已说明边界内支持
使用 .git 文件的关联 Git worktree 拒绝;需要 Git 历史时,使用有独立 Git 元数据的实际文件副本
已挂载符号链接,或仍指向隔离快照外部的挂载项 拒绝;将输入实际复制到选定站点或受支持的本地依赖内
未挂载的辅助符号链接 不复制到快照;这不代表其内容已验证
将排除的 public、resources、node_modules 或 tmp 目录作为输入的挂载项 作为必需源码时拒绝;将创作或生成源码放入专门的源码目录
自定义 HUGO_CONFIGDIR,未使用支持的 config 位置 拒绝;使用站点内 config 树,或显式选择站点内的 --config 文件
Hugo 内容适配器(_content.gotmpl) 不支持完整的启用输出枚举;check 与候选验证返回必要工作未完成
多主机语言配置 不支持完整产物验证;返回必要工作未完成,不将不同主机当成单一输出树

同样,禁用页面渲染或选择使某个启用语言缺少验证输出的 render segment,不能得到 完整检查通过的结果。这些是覆盖边界,不要求删除 worktree、replacement、符号链接 或创作内容。doctor 仍可以检查受支持的配置,但不会声称已完成产物构建。

选择检查并记录项目政策

项目需要显式检查政策时,在站点根目录创建普通文件 oink.yaml,在一个 YAML 文档中使用 schema_version: oink.policy/v1。语言、菜单、URL 和主题版本保留在 已有 Hugo/模块输入中。未知政策字段/分组、无效审阅和禁用的必需分组返回 2。

下面保留必需链接,并演示经审阅的问题与单独部署的 URL 范围。 请将示例路径和审阅元数据替换为项目的实际决策:

schema_version: oink.policy/v1
checks:
  links: {enabled: true, required: true}
rules:
  ANCHOR_MISSING: warning
exclusions:
  - rule_id: REFERENCE_MISSING
    file: docs/legacy/index.html
    reason: Reviewed legacy reference awaiting removal
    reviewed_by: site-maintainer
    reviewed_at: "2026-10-03T00:00:00Z"
external_scopes:
  - url: https://example.org/status/
    reason: Separately deployed status application
    reviewed_by: site-maintainer
    reviewed_at: "2026-10-03T00:00:00Z"

规则使用确切诊断 ID 和 error、warning 或 info。 排除 glob 使用规范相对路径,不支持递归 ** 和逃逸路径。 被排除的问题仍可见,附有 disposition: "excluded" 和审阅元数据。 检查不会把创建审阅记录作为副作用;政策不会改变必需构建/输入/工具失败和不支持覆盖的 2。

站点位于 https://example.org/manual/ 时,同 origin 的 /status/ HTML 引用通常会因位于发布 base path 之外而失败。经审阅的范围声明该应用单独部署, 但可访问性仍未检查。按完整路径段匹配,不包含 /status-other/。 范围不能隐藏 /manual/ 内缺失目标,也不能豁免机器输出的必需本地引用。

没有政策时,check 启用必需的链接、翻译和风格检查。check links、 check translations、check style 分别选择一个必需引擎;未选中分组报告 可选 not_checked。显式政策分组可以关闭可选检查。每次检查仍保留其严格 Hugo 前提。

声明翻译覆盖

先读取 check --json 的 data.pages 中 Hugo 实际页面身份,再声明源 Page.Path 范围与必需的已启用语言。路径是 Hugo 源页面身份,不受 slug、URL、别名或语言 前缀影响。扩展同一个 oink.yaml 对象;下面的完整示例同时声明受保护正文与基线路径:

schema_version: oink.policy/v1
checks:
  links: {enabled: true, required: true}
  translations: {enabled: true, required: true}
  style: {enabled: true, required: true}
translations:
  scopes:
    - path: /docs/handbook
      source_language: en
      required_languages: [zh]
      mode: localized
      drafts: include
      constraints:
        explicit_ids: true
        ids: [setup]
        placeholders: ["${SERVICE_NAME}"]
        code_labels: [bash]
        required_fields: [title]
        equal_fields: [weight]
style:
  protected:
    - file: content/docs/handbook.md
      literal: "${SERVICE_NAME}"
      count: 1
baseline: .oink/baseline.json

请使用项目实际页面路径、文件名、ID 和受保护字符串。mode 默认 localized, drafts 默认 include。严格模式配合 explicit_ids: true 要求完整的已识别 显式 ID 对应;本地化模式保护选定 ids。占位符数量、指定围栏代码、必需点分字段 和点分值相等分别是显式约束。其他正文、标题数量和代码可以不同。

drafts: ignore 跳过草稿源页面,并将草稿目标视为不可用;require-published 要求源页面与必需目标存在于生产视图。Hugo 已知但禁用的语言为可选 not_applicable;未知语言导致政策加载失败。没有范围时,检查已有默认语言配对及 重复关系,但不要求全站普遍本地化。JSON data.translations 分别展示缺失、草稿 和哈希审阅状态。显式不可发布的分析包含草稿/未来/过期页面,从不替代生产输出或 发布这些页面。

检查源码规则与来源

oink check style --site ./my-docs --json

通用规则检查已识别的显式 ID 和声明的受保护正文。解析器遵循 Hugo 生效的 markup.goldmark.parser.attribute.title 和 .block,以及 markup.goldmark.extensions.passthrough.enable 和配置的 .delimiters。 这些设置保留在 Hugo 配置中。解析器保留原始 UTF-8/CRLF/BOM 偏移,并接受未知但合法的 YAML/TOML/JSON front matter。代码、短代码主体、原始 HTML 和数学内容不参与 正文证据;围栏后面的属性不会被当作受支持的代码属性。必需源码语法不支持,或 声明的受保护输入不存在时,返回 2。

小型 OINK v1.1.0 原生目录对代码/表格冲突、弃用归属字段和公开主题丢弃的属性 提供建议。data.native_rule_provenance 记录不可变源码/许可证哈希。 只有实际公开模块缓存挂载经过 SHA 验证时才运行目录。其他版本、replacement、 vendor 副本和未知身份报告可选 native-theme-rules: not_checked,通用规则仍运行。 判断某个组件是否检查完整前,应先审阅这项覆盖。

审阅翻译并应用元数据计划

使用报告中的确切 Hugo ID 或无歧义捕获源文件名:

oink translations status --site ./my-docs --json
oink translations diff 'en:/docs/handbook' --site ./my-docs
oink translations review 'en:/docs/handbook' 'zh:/docs/handbook' \
  --site ./my-docs --reviewed-by site-maintainer \
  --reason 'Reviewed source and translation together' --plan /tmp/oink-review.json
oink plans apply /tmp/oink-review.json --site ./my-docs

审阅在候选验证后预览 .oink/translations.json(oink.translations/v1), 预览阶段不写站点。记录绑定完整源文件/译文的字节 SHA-256 和显式审阅人/理由/时间。 --reviewed-at RFC3339 可选,默认当前 UTC。无记录为 unknown;current、 source_changed、translation_changed、both_changed 描述审阅后的哈希变化, 不判断翻译准确度。修改时间不是审阅证据,diff 展示捕获的源码文本供比较。

明确确认已完成检查中审阅过的既有问题,并保持其可见:

oink baseline capture --site ./my-docs --reviewed-by site-maintainer \
  --reason 'Reviewed existing findings for this maintenance baseline' \
  --plan /tmp/oink-baseline.json
oink plans apply /tmp/oink-baseline.json --site ./my-docs

默认基线为 .oink/baseline.json(oink.baseline/v1);政策 baseline 可以 选择其他规范相对文件。确认过的确切规则、规范化位置/指针及条件仍保留 disposition: "baseline" 和审阅元数据。严重度变化不会改变指纹,新条件仍阻断。 必需但未完成的工作不能被捕获或经基线隐藏。

两种预览命令均要求审阅人和理由。--plan FILE 创建新的 oink.plan/v1 文件而 不覆盖;省略时只打印已验证计划。运行 plans apply 前,审阅可读 diff、站点、 文件列表及基础字节/模式保护条件。该命令重新验证隔离候选,拒绝过期保护条件、 逃逸、.git、符号链接和非普通文件,仅写入计划选定文件;这些命令不使用 --write。部分写入失败会还原本次拥有且未变化的文件,保留编辑器后续字节、模式 或删除状态。报告的恢复目录保留原始/并发证据。

预览并应用单站点主题升级

选择明确的版本标签。下面的命令验证候选站点,输出模块文件变更计划,但不应用:

oink upgrade --site ./my-docs --to v1.1.0 --json > upgrade-plan.json

普通文本显示统一模块 diff、模式变化和有界路由/alias/能力变化。JSON 中检查 data.plan_id、data.changes、data.comparison、基线/候选检查摘要与原始证据。 旧 URL/输出缺失会阻断更新,除非其旧输出文件处的实际重定向证明保留;未知定制 alias 身份保持未完成。这不证明普遍主题或浏览器兼容。应用重新验证的审阅计划时, 使用已记录 ID:

oink upgrade --site ./my-docs --to v1.1.0 --write \
  --expect-plan 'COPY_PLAN_ID_FROM_PREVIEW'

CLI 在候选验证通过后,只修改选定的 go.mod 与 go.sum 字节,并保留无关依赖、 replacement 指令、注释及无关的未提交工作。--write 拒绝这两个目标文件中的 未提交修改,并检测计划建立后的变化。恢复证据会指出备份位置,以及因文件被并发修改 而无法安全完成的回滚。

计划 ID 绑定当前复制源码字节/模式/清单和实际比较,不仅是模块文件文本。 后续源码/workspace/依赖修改需新预览,只应用选定模块文件。未知实际 pin 或变化/ 未知渲染器/环境不能通过。比较支持单个 HTTP(S) base origin/path,多主机输入保持 未完成。生成字节哈希也绑定 ID,因此非确定性模板可能需要重新预览。不自动迁移 配置,不支持变化交由人工审阅。

OINK 的 go.mod replace 会阻断这条公开 pin 升级流程。包含 _vendor 的站点也会 被拒绝,因为本版本不刷新 vendor 内容。请在单独、可审查的副本中修改目标 pin,显式 运行 hugo mod vendor,再审查并验证完整 vendor 变更。仅修改 go.mod 永远不会 被报告为 vendor 已升级。

通过 Hugo 预览与构建

oink dev --site ./my-docs -- --port 1315 --bind 127.0.0.1
oink build --site ./my-docs -- --minify

-- 后面的参数直接传给 Hugo。CLI 展示生效命令并转发进程取消。 dev 运行 hugo server;build 默认选择生产环境,并添加 --panicOnWarning。 这两项默认直接调用 Hugo,可能创建站点通常使用的产物与缓存文件,不执行 oink check 所包含的引用检查。

检查并导出一次构建

在 OINK_PUBLIC_BASE_URL 中设置实际发布 URL,预备站点的准确依赖,再使用新产物 目录和单独的新清单:

OINK_ARTIFACT_DIR=$(mktemp -d)
oink build --check --site ./my-docs --release \
  --base-url "$OINK_PUBLIC_BASE_URL" \
  --destination "$OINK_ARTIFACT_DIR/public" \
  --manifest "$OINK_ARTIFACT_DIR/build-manifest.json" --marker

仅当本次操作需要下载依赖或必需远程资源时,才添加 --network。示例/本地发布地址 属于发布错误;普通诊断报告警告。--release 也独立检查实际公开主题解析,不以本地 Git 历史或声明 pin 代替证据。

Hugo 只渲染一份隔离生产产物。CLI 检查、封装并导出同一目录树,不重新构建,也不 修改站点源码。必需覆盖未完成时返回 2,发现阻断项时返回 1;两种结果都不会 产生已验证导出。显式翻译范围政策需要被排除发布的 Hugo 身份时,返回 2。 可以运行独立 check/translations 获取完整不可发布维护视图,或明确选择生产 政策。命令不根据文件名推断身份。

目标必须是新目录或空目录,且父目录已存在。清单必须是公开产物树之外的新文件。 既有条目保持不变;部分导出失败后仍明确标记为未验证。可选 --marker 仅在 .well-known/oink-build.json 添加产物身份;不传该参数时不添加标记。本地 oink.artifact/v1 清单记录原始输入身份、已知 Git 状态、生效设置/主题/工具、 必需覆盖、Hugo 路由及准确文件摘要/模式,不包含本机绝对路径或日志,以 0600 模式保存。请将它保留在上传树之外。

受管理构建仅允许 -- 后的 --minify、--gc、--ignoreCache 与 --noTimes, 以及可选布尔形式 =true/=false。上文普通 build 示例仍透明透传 Hugo 参数。

验证产物与已部署站点

上传前立即离线检查导出目录:

oink artifacts verify --artifact "$OINK_ARTIFACT_DIR/public" \
  --manifest "$OINK_ARTIFACT_DIR/build-manifest.json"

这项检查比对准确文件集合、字节及完整模式。文件缺失、新增或修改会使先前身份失效。 上传这个目录,不再构建;启用标记时保留隐藏的 .well-known 文件。

完成单独授权的部署后,显式验证公开 URL:

oink verify --site "$OINK_PUBLIC_BASE_URL" \
  --manifest "$OINK_ARTIFACT_DIR/build-manifest.json" --network

验证读取每个声明文件与不同的实际 Hugo 路由,包括语言/子路径 URL,并比对有界 解码后的响应摘要、已记录的 HTML 规范 URL/语言身份及启用的标记。HTTP 无法检查本地 文件模式。错误内容、soft-404 或不同的已捕获身份返回 1。超时、认证/限流失败、 服务不可用及缺少必需标记返回 2;离开选定 origin/path 的跳转会被阻止。 命令不发现或发送凭据。构建的 --network 权限不授权这次后续请求或任何上传。

已撤下 CI 生成

移除 ci init。CI 配置保留在站点或 Starter 中。 本地 CLI 验证不执行托管 CI,也不部署站点。plans apply 拒绝旧 CI 计划。

检查显式登记的站点

R6 受支持本地范围已接受

工作区与适配器示例通过归属/运行时、实际协议、四消费者一致性/保护及规范 源码/渲染门禁。A07/A15 受支持范围已在 R6 记录中本地接受。 这些示例不代表 CLI 已公开发布或平台刷新已经完成。

在选定项目旁创建独立登记文件,例如 oink.workspace.yaml。站点字段只有 name 与 directory;Hugo 设置保留在各站,检查政策保留在该站的 oink.yaml。

schema_version: oink.workspace/v1
sites:
  - name: docs
    directory: ../docs-site
  - name: blog
    directory: ../blog-site
oink workspace list --workspace ./oink.workspace.yaml
oink workspace check --workspace ./oink.workspace.yaml --offline --json
oink workspace check links --workspace ./oink.workspace.yaml \
  --sites docs,blog --offline --json
oink check style --workspace ./oink.workspace.yaml --site docs --offline --json
命令 选择范围
workspace list --workspace FILE 不运行 Hugo,只列出显式条目
workspace check [GROUP] --workspace FILE [--sites NAME,NAME] 按登记顺序检查全部或准确子集
check ... --workspace FILE --site NAME 对一个登记名称运行普通单站检查
plans apply FILE --workspace FILE --site NAME 重新验证并只应用绑定该名称规范目录的计划

名称是区分大小写的 ASCII 标识符,符合 [A-Za-z][A-Za-z0-9_-]{0,63}。 非符号链接的普通登记文件只含一份严格 YAML 文档、1–64 个不重叠站点,最多 256 KiB。目录是相对其实际父目录的字面路径,或绝对路径;不展开环境变量/glob, 不发现同级站点。规范别名识别同一站点,不能重复登记。缺失目录仍列出;检查它 返回 2,其余显式站点仍继续检查。汇总优先级是 2、1、0,保留完整逐站 发现项与覆盖。省略 --sites 选择全部登记站点;显式列表拒绝空项、重复项和未知 名称,仍按登记顺序处理。

直接命令必须提供 --site NAME,没有默认登记站点。init、artifacts、verify 不接受登记选择。将审阅计划保存到站点外,再显式应用到同一个名称:

oink translations review en:/docs/manual zh:/docs/manual \
  --workspace ./oink.workspace.yaml --site docs \
  --reviewed-by 'Maintainer' --reason 'Reviewed terminology and examples' \
  --reviewed-at 2026-10-03T00:00:00Z --plan ./review.plan.json --offline
oink plans apply ./review.plan.json \
  --workspace ./oink.workspace.yaml --site docs --offline

审阅选择器使用你自己站点检查返回的实际页面身份。将绑定 docs 的计划改选为 blog 时,在源码写入前返回 2。预览、验证、新鲜度与字节/模式保护和直接单站 使用相同;不会自动更新其他登记或邻近站点。

配置已预备的可选工具

CLI 不安装 markdownlint、Vale 或 lychee。独立预备工具后,在选定站点的 oink.yaml 中增加显式配置。当前协议为 markdownlint-cli 0.49.1、Vale 3.24.0 与 lychee 0.24.2;其他上报版本在完成验证前仍不受支持。

schema_version: oink.policy/v1
tools:
  markdownlint:
    required: false
    config: .markdownlint.yaml
    timeout_seconds: 60
  vale:
    required: false
    config: .vale.ini
    timeout_seconds: 60
  lychee:
    required: false
    config: lychee.toml
    timeout_seconds: 60

enabled 默认 true,required 默认 false,command 默认与工具种类同名。 可以按名称或绝对路径选择一个已预备可执行文件;命令不是 shell 片段。配置必须是 捕获站点内的干净相对路径。进程时间默认 60 秒,非默认值限 1–300。缺失的可选工具 显示遗漏;必需工具缺失或协议不受支持返回 2。问题基线或降低规则严重度不能把 必需工作未完成变成成功。

Markdownlint 与 Vale 归属 style;lychee 归属 links。选择你准备运行工具的 检查组:

oink check style --workspace ./oink.workspace.yaml --site docs --offline --json
oink check links --workspace ./oink.workspace.yaml --site docs --network --json

第二条命令显式允许实际外部 HTTP 请求。没有 --network 时,不调用 lychee: 可选覆盖为 not_checked,必需覆盖返回 2。原生本地链接检查通过不能证明外部 可用性。HTTP 401、403、408、425、429、5xx、DNS/TLS 失败与超时 是不确定结果,不是确定的断链。其他失败 4xx 响应是类型化发现项。外部位置保持 实际输出文件与 DOM pointer;CLI 不猜测其 Markdown 行号。

Markdownlint 使用声明式 JSON、YAML 或 TOML,例如:

default: true
MD013: false

不支持 JS/JSONC 配置、自定义规则与 extends。CLI 将私有规则对象放在不可预测 JSON pointer 后,上游 rc 数据不会改变其有效规则。Vale 需要显式 INI 与捕获的风格。 受支持的最小配置是:

StylesPath = styles
MinAlertLevel = warning

[*.md]
BasedOnStyles = Project

在 styles/Project/ 提供声明式规则文件。支持的规则种类是 existence、 substitution、repetition、occurrence、consistency、capitalization 与 sequence。Actions、scripts、packages、sync、转换资产与风格流水线需要人工 审阅,此适配器不执行它们。Lychee 只接受这些有界请求设置:

timeout = 10
max_retries = 0
max_concurrency = 8

允许范围为 1–300 秒、0–3 次重试、1–32 个并发请求。还接受字面 cache = false, 拒绝 cache = true。关闭缓存与预处理器,不接受任意额外工具参数。适配器不修复 或格式化源文件。代码正文不参与源码归因;markdownlint 仍能读取 Markdown 结构 和围栏/行内代码边界,Vale 使用纯正文遮蔽。私有遮蔽保留 front matter、短代码、 原始 HTML、已配置数学公式与属性周围已证明的 UTF-8/BOM/CRLF 边界;排除/生成 文本的发现项保留为遗漏。文字工具只读取已捕获的站点自有 Markdown。

解释退出码之前,检查 data.adapters、adapter.KIND 覆盖和原始 evidence。 每个适配器保留版本/可执行文件/配置哈希与协议来源。不传入调用者的代理 URL/凭据 与 Node 预加载设置;已验证运行时可以保留字面的 NO_PROXY/no_proxy 主机列表 数据。这不禁用所有操作系统代理路由,也不构成网络沙箱。网络检查不验证外部片段、 浏览器行为或远端内容身份。

已撤下本地 Studio

CLI 移除 studio。使用普通编辑器与 oink dev 预览站点;通过 inspect 及结构化报告读取维护事实。带日期 R7 验收保留为对应输入的历史证据。

已撤下 Studio 视图

使用 inspect、check 与结构化报告读取页面和质量事实。

已撤下浏览器目标

Studio 浏览器测试目标随实现移除。当前 CLI 验证使用 Go 与真实 Hugo 测试。

已撤下通用编辑

移除 edit 与 Studio 编辑。使用普通编辑器修改源码,再运行 check。 new、move、审阅记录与基线计划继续保留候选验证和字节/模式保护。 旧编辑计划会被拒绝,带日期 R8 记录保留为历史证据。

已撤下 edit 命令

移除 edit text|field|snippet|attachment 命令族。 保留的有界文件流程见 new --help 或 move --help。

已撤下 Studio 编辑

CLI 不提供编辑器,也不接受浏览器 Apply 请求。

保留计划审阅

保留的预览展示完整拟议 diff。保存新计划后,显式运行 plans apply FILE --site DIR。候选验证、源码/外部输入保护与并发编辑恢复仍为必要条件。

网络与离线运行

默认禁止网络访问;--offline 可以显式表达这一选择。缺少依赖会返回未完成结果。 CLI 不安装 Hugo,不下载 Go 工具链,不修改全局配置,也不启用遥测。只有明确需要时, 才允许当前操作联网:

oink check --site ./my-docs --network

--network 和 --offline 不能同时使用。诊断与验证操作使用临时缓存,在其中下载 依赖,并不意味着下一次离线运行已有持久缓存。需要可重复的离线工作流时,应在普通 Go 模块缓存中预备确切版本,并按上文显式设置 GOMODCACHE,同时包含站点所需的 全部传递依赖。隔离验证复用已预备的模块下载制品,不复用 Hugo 全局远程资源 (GetRemote)缓存。仅预热远程资源缓存,不能使这项检查离线运行。应将必需的远程 内容实际保存为站点本地资源,或为该次构建显式使用 --network。主题已经以内置本地 文件提供的资源无需这样的下载。

文本、JSON、YAML 与自动化

oink check --site ./my-docs
oink check --site ./my-docs --verbose
oink check --site ./my-docs -J > check.json 2> check.log
oink check --site ./my-docs -Y > check.yaml 2> check.log
oink translations review --help
选项 输出
默认 简洁彩色英文文本
--json、-J 一个 JSON oink.result/v1 对象
--yaml、-Y 一个具有相同结果字段与类型的 YAML 文档
--verbose、-v 全部发现、覆盖明细与工具日志
--no-color 无颜色英文文本

只能选择一种结构化格式。非空 NO_COLOR 或 TERM=dumb 也会关闭文本颜色。 结构化输出不添加终端颜色,工具日志写入 stderr。--format json|yaml 与 --non-interactive 保留为隐藏兼容选项;所有命令均不交互。

默认文本展示状态、计数、最多八条活动发现及明确的未检查覆盖。详细事实与已审阅 发现保留在结构化结果中。计划与升级预览展示完整 diff。Cobra 管理命令分发与各级 帮助。CLI 提示采用 ASD-STE100 风格的简短主动英文句,不宣称认证;用户内容与 外部工具证据保留原语言。

退出码 含义
0 请求的工作已完成,且没有阻断项
1 已完成的检查发现政策问题
2 必要工作未完成,包括工具、构建或 I/O 失败

应同时检查退出码与覆盖状态。doctor 返回零不能证明构建通过,静态检查成功也不能 证明浏览器行为或公开部署正确。这些命令不会提交、推送、发布主题或部署站点。