# 追踪 Homebrew 每天新增了哪些包

日期: 2026-06-22T01:40:25Z
摘要: Homebrew 官方没有「每日新增包」页面。用 GitHub tree API 对比相邻两天的目录文件列表，再调 LLM 翻译描述，搭了一个每天自动更新的追踪工具。
关键词:
- Homebrew
- GitHub API
- tree API
- LLM 翻译
- 自动化
- 定时任务

---

用 Homebrew 的人都会有一个好奇：每天到底新增了哪些包。Homebrew 官方提供了一个 [formulae.brew.sh](https://formulae.brew.sh/formula) 页面，列出所有当前可用的 formula 和 cask，八千多个包按字母排开。但它只给当前快照，没有「今天新增了什么」这个视图。GitHub 上的 [homebrew-core](https://github.com/Homebrew/homebrew-core) 仓库有完整的提交历史，八十多万次 commit，却没有按日期筛选新增包的界面。

我想把这个缺口补上，做成一个每天自动更新的页面，描述还要翻译成中文。

第一步是找数据源。formulae.brew.sh 的 [JSON API](https://formulae.brew.sh/docs/api/) 只返回当前所有包的元数据，没有历史快照。要做「新增」，必须对比两天之间的差异。最直觉的办法是 clone 整个 homebrew-core 仓库，用 `git log --diff-filter=A --since --until` 查指定日期新增的文件。但 homebrew-core 有八十多万次 commit，完整 clone 下来超过 1GB。我的服务器只有 1G 内存 1 核 CPU，clone 过程直接把机器拖崩了。

退一步想，其实不需要完整历史。只要知道某一天仓库里有哪些 `.rb` 文件，再对比前一天，多出来的就是新增。GitHub 的 [tree API](https://docs.github.com/en/rest/git/trees) 正好做这件事。传一个 commit sha 进去，加 `recursive=1` 参数，一次性返回那个时间点仓库里所有文件的路径列表。上限是十万条目或 7MB，homebrew-core 的 Formula 目录有八千五百多个文件，远没到上限。

具体做法分三步。先调 GitHub commits API 取相邻两天各自最后一个 commit 的 sha。再用这两个 sha 分别拉 tree，提取 `Formula/` 和 `Casks/` 目录下的 `.rb` 文件名。两个集合做差集，多出来的就是当天新增的包名。

拿到包名之后，描述、主页、版本这些元数据从 formulae.brew.sh 的当前 API 查。新增包大概率还在当前列表里，查不到的就跳过。最后把英文描述批量发给 LLM 翻译成中文，保留专有名词和命令名的原文。用的是 DeepSeek V4 Flash，四十个描述打包一次请求，返回 JSON 映射，几秒处理完。

翻译这条要注意一个细节。prompt 里必须明确「只返回 JSON 对象，键为 name，值为中文翻译，不要任何解释」。否则模型会加一句「以下是翻译结果」之类的前缀，JSON 解析直接失败。即便加了约束，偶尔还是会遇到格式漂移。脚本里做了兜底，解析失败就回退到英文原文，不让一个翻译错误中断整个流程。

整个流程写成两个脚本。`brew-daily.ts` 跑当天，对比昨天和今天的 tree，输出当日的 JSON 文件。`brew-daily-backfill.ts` 接受一个日期参数，可以回填任意历史日期，原理相同。两个脚本都往 `public/tools/brew-daily/data/` 目录写 `<date>.json` 和一个 `index.json` 索引。页面是纯静态 HTML，客户端 JavaScript 加载 JSON 渲染，日期选择器切换不同日期的数据。

定时任务用 cron。每天 06:00 UTC 跑一次当天脚本，结果直接写到服务器上的静态目录。data 目录被 gitignore 忽略，数据只在服务器本地，页面本身入 git。这样 git 历史干净，数据每天自动滚动更新。

中间踩了一个很实在的坑。我在服务器上试过用 SSH 跑 `git clone`，命令超时后本地终端显示「Command aborted」，我以为进程已经停了。实际上 SSH 超时只断开本地连接，远端进程还在跑。那个 `git index-pack` 一直在后台吃 42% CPU，把 1G1C 的服务器资源占满，博客服务被拖得反复崩溃重启。排查时看到 systemctl 日志里 fanshikun 服务每隔几分钟就 exit 一次，restart counter 跑到十七次，才意识到是后台 clone 没杀掉。

教训很直接。SSH 跑长任务必须用 `timeout` 包裹，或者超时后主动 `ssh hkl 'pkill -f ...'` 清理远端进程。光看本地终端的「aborted」会误判远端状态。1G1C 的机器根本不该跑 clone 这种重活，数据源的活应该交给 API，clone 留给本地 mac。

工具上线后，[页面](https://fanshikun.com/tools/brew-daily/)每天早上更新一次。回填历史日期只要在服务器跑一行 `bun scripts/brew-daily-backfill.ts --date 2026-06-21`，几秒出结果。六二十一号那天新增了三个包，一个是 GitHub Actions 的语言服务器，一个是 8BitDo 手柄固件更新器，一个是叫 Palmier Pro 的 AI 视频编辑器。翻译质量不错，「Language server for GitHub Actions YAML files」译成「GitHub Actions YAML 文件的语言服务器」，专有名词都保留了。

这个方案有几个已知限制。tree API 只能发现文件的新增和删除，识别不了重命名，一个包从 `Formula/a/axxx.rb` 改名到 `Formula/b/bxxx.rb` 会被算成一次删除加一次新增。也识别不了迁移，包从 cask 转 formula 会跨目录移动，同样被算成两次独立变化。还有一类情况是同一天内新增又被移除，如果恰好在那天最后一次 commit 时已经不在了，就完全查不到。这些边界情况数量很少，对这个工具的用途可以接受。

这个工具本身没什么技术难度。核心就是发现 formulae.brew.sh 没有历史视图，GitHub tree API 能补上这个缺口，再把 LLM 翻译接到流程末尾。真正花时间的是数据源选型和那个 SSH 进程的坑。工具做完，每天打开页面扫一眼，能发现一些平时不会注意到的有趣项目。

***

相关文章：

- [让博客对 Agent 友好](/让博客对-agent-友好/)
- [国内云服务器加速 Bun 安装脚本的三种方式](/国内云服务器加速-Bun-安装脚本的三种方式/)
- [用 Bun WebView 给博客搭了一个 Mermaid 渲染引擎](/bun-webview-mermaid-renderer/)
- [简单需求自建](/简单需求自建/)
- [模型优先](/model-first-then-agent/)
