mcpField
H
homebrew-cask-authoring

homebrew-cask-authoring

github.com/connorads开发18126 次安装2 天前更新
代码仓库

关于 homebrew-cask-authoring

这是一项用于编写 Homebrew Cask 贡献的技能,补充样式检查无法判断的事项。它涵盖资格评估、Cask 结构、验证、清理规则及拉取请求流程。

主要功能

  1. 01Cask 资格与令牌命名
  2. 02安装及清理配置指导
  3. 03架构与操作系统专属 Cask
  4. 04审计、安装和 zap 验证
  5. 05拉取请求与 AI 披露规范

适用场景

  1. 01评估软件是否符合新增 Cask 的条件
  2. 02为 macOS 和 Linux 制品起草 Cask
  3. 03在审查前检查卸载和 zap 行为
  4. 04准备 Homebrew Cask 拉取请求

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/connorads/dotfiles --skill homebrew-cask-authoring

安装后在 Claude Code 中输入/homebrew-cask-authoring确认已加载。

附带文件references/homebrew-cask-contribution-workflow.md

详细介绍

Homebrew Cask 编写

Homebrew Cask 维护者会在不追问的情况下合并这项更改吗?

Homebrew 的 cops 和审计会强制执行布局、顺序和大多数语法要求。本技能涵盖它们无法处理的内容:资格、命名、清理路径、测试和 PR 行为。如果此处的规则与 brew style/brew audit 不一致,以工具为准——工具会跟进 Homebrew 的当前版本,而本文档不会。

操作规则

  • 提交 PR 前,获取 homebrew-cask 自身的 Agent 政策并遵循: gh api repos/Homebrew/homebrew-cask/contents/AGENTS.md -H 'Accept: application/vnd.github.raw'。 官方文档:Cask Cookbook、 Acceptable Casks。
  • 保持 cask 精简:仅包含正确安装、卸载和清理所需的 stanza。
  • 绝不要写 url ..., verified:。此写法已弃用且会被忽略;编辑任何 cask 时都应将其移除。
  • 仅支持一种操作系统的 cask 必须在顶层声明 depends_on :macos(或带版本的 depends_on macos: :<sym>)或 depends_on :linux。制品类型不再隐含操作系统。
  • 跨平台 cask 不应声明顶层操作系统依赖。应在 on_macos(app、pkg、suite 等)或 on_linux(app_image)中限定特定操作系统的制品;binary 可跨平台使用。将 depends_on macos: 放在 on_macos 内——放在顶层会导致 Linux 不适用。
  • 执行任何 rm、tap 或系统更改前,都要明确说明。测试后恢复 Homebrew 的标准状态,除非用户要求保留覆盖设置。

预检(新 cask)

  1. 知名度(政策): GitHub 项目的 fork 数或关注者数低于 30,或 star 数低于 75,很可能会被拒绝;如果 PR 作者拥有上游仓库,则门槛提高至 3 倍(90/90/225)。仅限 Linux 和 AppImage cask 不享有豁免。
  2. 存在时间:仓库和主页域名都必须至少存在 30 天,否则无论 cask 质量如何,brew audit --new 都会失败。
  3. Gatekeeper:macOS 制品必须经过签名和公证 (spctl -a -vv <App>.app)。未签名的应用不符合资格;绝不要建议使用 --no-quarantine 或停用 Gatekeeper 作为变通方法。
  4. Rosetta:当 macOS 27 成为最新稳定版 macOS 后,新的 requires_rosetta / 仅支持 x86_64 的 macOS cask 将不再符合资格。起草此类 cask 前请先确认。仅限 Linux 的 cask 不受此限制。
  5. 正确的仓库:没有已编译应用的开源 CLI 应归入 homebrew/core。被 homebrew/core 拒绝并不意味着它就符合 cask 的资格。
  6. 先例:搜索已关闭但未合并的 PR 和开放的 PR,查找该 token。 不要因无法解决的原因再次提交已被拒绝的内容。
  7. Linux 构建:检查上游是否提供 AppImage。审核者会要求新 cask 提供它,因此若存在就应一并加入。
  8. 预发布版本:如果上游将每个 GitHub 版本都标记为预发布版本,在线审计会失败,并显示 <tag> is a GitHub pre-release。在同一提交中,将 "<token>": "all" 加入 audit_exceptions/github_prerelease_allowlist.json (先例:agent-tars、duplicati);如果之后出现非预发布版本,"all" 也会报错。将其插入相邻条目旁——该文件并未严格排序,因此重新排序会产生与当前更改无关的 diff。请在 PR 正文中说明理由。

工作流

1) 令牌

先运行 brew generate-cask-token "<App Name>.app",再应用它未涵盖的判断规则:

  • 除非该应用不是移植版,且「Mac」与名称不可分割(playonmac),否则删除「Mac」。
  • 默认删除「Desktop」。一位维护者为桌面应用接受了 executor,之后 Homebrew/core 中的 CLI 使用了 executor-cli。哪个组件先进入 Homebrew,裸名称就归哪个组件。
  • 仅当「Desktop」是品牌名称(docker-desktop、ltx-desktop),或 Homebrew 中已经存在以裸名称命名的同系列项目时,才保留「Desktop」。仅存在于上游(npm、crates.io)的 CLI 不构成理由。
  • cask token mentions desktop 审计仅在严格模式下运行(即使用 --new 时触发)。无论如何选择,都要在 PR 正文中说明理由。
  • 变体:@beta、@nightly、@latest、@<major>。

写入文件前,先让用户确认令牌。

2) 起草

使用 brew create --cask <url> --set-name <token> 创建模板,然后精简为:

cask "token" do
  version "1.2.3"
  sha256 "..."

  url "https://example.com/app-#{version}.dmg"
  name "Official App Name"
  desc "Short one-line description"
  homepage "https://example.com/"

  depends_on :macos

  app "AppName.app"
end
  • desc:描述事实,不含营销内容,不出现平台相关措辞(如「适用于 macOS」),少于 80 个字符。
  • 如果应用需要更新的最低系统版本,将 depends_on :macos 替换为 depends_on macos: :<sym>。brew audit --cask --online --fix <token> 会从应用包中推导该值,但仅适用于没有 on_* 块的 cask。符号表:请参阅参考资料。
3) 架构

检查二进制文件,而非厂商宣传:

lipo -archs "/Volumes/<Vol>/<AppName>.app/Contents/MacOS/<AppName>"
  • 仅支持 arm64:添加 depends_on arch: :arm64,否则 Intel 用户会安装无法运行的应用。
  • 通用版:无需架构限制。
  • 不同 CPU 提供不同下载、但版本相同:使用 arch arm: ..., intel: ...,并配合 sha256 arm: ..., intel: ...。
  • 不同 CPU 提供不同版本:使用 on_arm / on_intel 块。
4)卸载与清理
  • pkg 和 installer(pkgutil:、launchctl: 等)必须使用 uninstall。
  • uninstall quit: 会在卸载、升级和重新安装时运行;Homebrew 会在升级后重新打开应用。除非设置 on_upgrade: :signal,否则升级时会跳过 signal:。
  • 如果模态窗口(例如首次运行时的权限面板)阻塞了应用的运行循环,应用可能会忽略 quit:。CI 的 zap-check 会在全新运行器上启动应用,因此会遇到这个问题,而已授予权限的本地安装则不会;随后 CI 会因“Some launch jobs were not unloaded”而失败。signal: 在 macOS 26 上不起作用:Homebrew 会通过 launchd 标签查找进程,而标签现在以 UUID 结尾(application.<id>.<n>.<n>.<UUID>),会被其模式拒绝。请在 quit: 旁使用 launchctl: "application.<bundle-id>.*"(先例:shutter-encoder、cmux);移除任务即可结束进程。
  • launchctl: 会再次使用 sudo 检查每个任务,因此即使是用户级任务,本地卸载也会提示输入密码。非 sudo 检查已将其移除;取消密码提示是安全的。CI 的 sudo 无需密码。
  • 如果应用有辅助进程(Contents/Helpers/,或运行时执行 pgrep -lf <AppName> 能查到),quit: 中必须包含每个 bundle ID。只要 ID 至少包含 3 个以点分隔的部分,就可以使用通配符("com.vendor.*")。
  • zap 对审核而言是可选项,但评审者期望新 cask 包含此项:
    1. 安装、启动并使用应用(登录、实际操作)——某些路径(~/Library/HTTPStorages/<id>、会话缓存)只有使用后才会出现。
    2. 运行 brew generate-zap <token>(如果 cask 尚不存在,则使用 --name "<App Name>")。如果出现提示要求授予完全磁盘访问权限的错误,请将权限授予终端后重试。检查输出;其中包含无关内容。
    3. generate-zap 会涵盖 ~/Library 和 ~/.<app> 点目录,不包括 XDG 路径。如果执行 --zap 并重新安装后状态仍然保留,请在上游源码中搜索 os.homedir()、env-paths、xdg。 它也只会匹配应用名称,因此当状态以 CLI 或 token 命名时(~/Library/Caches/<cli>),会报告“无需 zap 段落”。还应在 ~/Library 中搜索 token 和 bundle ID,并在上游源码中搜索路径拼接代码;有些目录只有在使用某项功能后才会出现。
    4. 提交 PR 后,查看 CI 的 zap-check 作业摘要,了解它认为缺失的路径。
  • Keystone/GoogleUpdater 风格的共享组件只能放在 zap 中,绝不能放在 uninstall 中。
5)livecheck
  • 如果默认检查能找到版本,就省略 livecheck。只有确实有需求时(预发布版本、没有资源文件的发布版本、来源有误)才添加代码块。
  • 对于 Sparkle 应用,使用 brew find-appcast <path>.app 查找其 feed。
  • :github_latest / :github_releases 仅在选择启用时使用;Git 标签或上游 feed 不可用时才使用。它们匹配的是 tag_name,而不是资源文件名。
  • strategy :extract_plist 和 version :latest 会自动从 autobump 中排除;无需使用 no_autobump!。
6)跨平台(macOS + Linux AppImage)
  • 每个操作系统对应的字符串应放在顶层 arch(intel: on_system_conditional(macos: "x64", linux: "x86_64"))、os 或局部 on_system_conditional 中——都必须放在 version 之前。
  • 使用一个顶层 sha256,并按 arm:、intel:、arm64_linux:、x86_64_linux: 键控(只包含实际存在的键)。绝不要将 sha256 嵌套在 on_macos/on_linux 中。
  • on_macos / on_linux 代码块放在 sha256 之后、url 之前。
  • app_image "<file>", target: "<App>.AppImage"——目标中不得包含版本号。

四架构、单架构 Linux、通用 macOS 的模板,depends_on macos: 符号表以及 app_image 的行为,参见 references/homebrew-cask-contribution-workflow.md。

7) 验证

从本地的 homebrew/cask 检出目录运行(设置方法:参考资料):

brew style --fix <token>
brew audit --cask --online --os=all --arch=all <token>
brew audit --cask --new <token>                          # new casks; implies --strict --online
brew lgtm --online                                       # final gate; stage the cask first
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --cask <token>
brew uninstall --cask <token>
  • 成功时,brew audit 不会输出任何内容。
  • brew lgtm 会与本地 main 分支而不是 origin/main 比较差异。在过期的检出目录中,它会审计上游更改过的所有 cask(并下载其制品)。先运行 git fetch origin && git rebase origin/main,然后运行 git branch -f main origin/main;git diff --name-only main 应只列出你的文件。
  • 仅使用 --online 时只审计主机 OS/架构;--os=all --arch=all 则可在 Mac 上覆盖 on_linux。
  • 按 token 安装和卸载,切勿使用文件路径。
  • 在 TTY(tmux、Agent PTY)中,如果 brew install 要拉取依赖项,会要求确认;请传入 -y。

在应用运行时验证 zap:

HOMEBREW_NO_INSTALL_FROM_API=1 brew install --cask <token>
open "/Applications/<AppName>.app"     # log in, use it
brew uninstall --zap --cask <token>
pgrep -lf <AppName>                    # empty, or add bundle IDs to uninstall quit:

普通 uninstall 后重新安装应保留登录状态;使用 --zap 后则不应保留。这可以确认 zap 针对的是真实用户状态。

uninstall --zap 使用安装时记录的段落(Caskroom/<token>/.metadata/),而不是你的工作副本。编辑 zap 后:先卸载,再安装,然后运行 uninstall --zap。

8) PR
  • 为现有 cask 更新版本:brew bump --open-pr <token>(或 brew bump-cask-pr <token> --version <new>)。手动流程适用于新建 cask 和更改段落。
  • 每个 PR 提交一个 cask,尽量缩小差异,不顺手调整格式。基准分支为 main。
  • 提交主题(不超过 50 个字符):token 1.2.3 (new cask)、token 1.2.3 或 token: description。
  • 开 PR 时,每个 cask 只提交一个提交。开 PR 后,将审查和 CI 修复作为新提交推送(参见 homebrew-cask AGENTS.md)。仅在维护者要求时才压缩提交;CONTRIBUTING.md 和文档介绍了压缩提交,因此请预期会收到此要求。
  • PR 正文:保留模板。在检查清单上方添加一句说明文字(“为 App 添加一个 cask,……”),不要只放一个 URL。仅勾选已完成的项目。 不要添加冗长日志或 AI 分析。
9) AI 使用披露

遵循 负责任地使用 AI 和模板:

  • 人类只有在审查输出(包括 zap 路径)后,才勾选 AI 复选框。
  • 在其下方简要说明:使用的工具/模型、使用方式,以及人类手动验证的内容(安装、登录、使用、推导 zap、应用运行时卸载)。提及测试中发现的任何不明显问题,例如某个辅助程序需要第二个 quit: ID。
  • 提交中不要添加 Co-Authored-By、Assisted-by 或类似的 AI 尾注。
  • 人类应不借助 AI 回答维护者的问题和审查意见。Agent 不会起草或发布这些回复。
  • 非维护者同一时间最多只能有一个 AI 辅助的 PR 处于打开状态。

评论

支持 Markdown