从开源清理工具到付费 Mac 应用,用户教会了我如何做产品:Mole

最近我写了不少关于独立开发的思考,想着要汇总一下,就把 Mole 从开源 CLI 做到 Mac 付费软件这一路聊一聊:我当时是怎么想的,哪些事情做下来真的有用,也许能给正在做自己作品的朋友一些输入。

去年国庆我在三亚的泳池边写了几百行代码,做了个 Mac 清理的命令行工具 Mole CLI 开源到 GitHub 上,本来只想给自己和同事用。结果不到一年收了 60K star,陆续发了 50 多个版本,121 位来自全球各地的开发者提交过代码,解决掉近 800 个功能建议和 Bug。

其实我一直没太意识到用的人有多少,直到有一次,因为在 README 上挂了两张用 Vercel 加速的图片,流量把账单跑超了,欠了 Vercel 80 刀。当时才反应过来,桌面端可以做了。

之前收到最多的一类邮件来自国外用户,大意都差不多:我父母也用 Mac,我妹妹也用,但他们不会开终端,能不能做一个不用敲命令就能用的版本。这件事拖了挺久,主要是觉得 CLI 本身还没到成熟的地步。等 CLI 跑了大半年,哪些能删、删到什么程度算安全,心里有底了才开始做桌面版,做到自己敢天天用了才发出去。

当天晚上十点发布,那一夜通知一直在响,法国、德国各种币种都有,后来为了睡觉把邮箱通知关了。后面几个月一直在加东西,等于是一批用户先掏了钱,再陪着我把它做完。CLI 没有任何变化,照旧开源免费,也会一直更新,付费的只有桌面版。

桌面版做出来之后,我自己用得最多的反而是清理,因为我这台 Mac 真的快被 AI 撑爆了。我几乎全天开着 Claude Code 和 Codex 写东西,一开始没在意,后来才发现 AI 留下的垃圾跟以前的软件很不一样,大概是三类。

第一类是编译产物,这个不新鲜,但 AI 把量级放大了。以前一天手写几百行代码编译三五次,现在一个下午让 agent 跑十几轮,每轮都要编译一次。Rust 项目的 target、前端的 .next 和 dist、Xcode 的 DerivedData 增长很快,我自己有一次清出 86G,全是这些东西。

第二类是 AI 工具自己留下的旧版本,Claude Code、Cursor Agent、GitHub Copilot 这几个命令行工具都是自动更新的。更新方式是把新版本整个下载到一个新的版本目录,一个版本约 250MB,旧的不会删,几个月下来这里积着十几个再也用不到的版本。

第三类是模型文件,Ollama 和 LM Studio 拉下来的模型、HuggingFace 的缓存,常常有几十 G。

前两类 Mole 会清,第三类不碰。后来我慢慢把这件事想成三档,扫到的每样东西先归个类,再决定它默认要不要勾上。

第一档可再生,HTTP 缓存、GPU 缓存、编译产物和多数日志都算,相关的 App 退出了、路径也明确,就可以清。第二档重建代价高,包管理器的注册缓存、本地模型权重、iOS 的 DeviceSupport 都能重建,但要花网络和时间,得让用户自己过一眼。第三档不可替代,聊天记录、邮件库、照片图库、手上正做着的项目状态都在里面,我觉得这些东西就不该放进一键清理的列表。

这三档压成同一份「安全可删」的清单当然省事,代价是替用户把决定做了。清理页的十类项目就是按这个顺序排的,可再生的缓存排在最前面,越往下越需要自己看一眼。

target、build、dist、__pycache__、DerivedData 这些删掉以后重新编译一次就回来了,代价是几分钟 CPU。node_modules、Pods、venv、vendor 看着也是依赖目录,但删了必须重新联网下载,在高铁上或者飞机上想跑一下项目就只能干等。这两类看着差不多,很容易一起当垃圾清掉,Mole CLI 早期就是这样,后来专门把所有下载类的目录从 Mac 版的清理列表里摘了出去。

模型是这里面最重的一类,几十 G 重下一遍是灾难,而且通用清理工具就算想帮你删也删不对。Ollama 把模型拆成一堆按哈希命名的块,多个模型可能共用同一块,ollama rm 会先算清楚还有没有别人在引用才敢释放。你从文件系统上直接删掉一个看着很大的块,很可能把另一个模型弄坏。这种引用关系只有工具自己清楚。

所以 ~/.ollama/models、~/.cache/huggingface 这类路径在代码里是写死的保护名单,扫描阶段根本不会出现,只在磁盘分析那边显示占用大小,模型本身交回给 Ollama、LM Studio 自己管。

还有一类东西比模型更不能动,是 AI 的会话记录。~/.codex/sessions、~/.claude/projects、~/.grok/sessions 里存的是你和 AI 几个月甚至一年的完整对话,里面有当时的思路、被否掉的方案、每一处为什么这么改的原因,删掉就真的没了,说起来比代码本身还珍贵。所以这几个路径在 Mole 里永远不会清,放了多久没动过都一样,同样受保护的还有 memories、plans、skills 和生成的图片。

这些保护名单不是一开始就想好的,基本都是踩出来的。最蠢的一次是 com.apple.e5rt.e5bundlecache,名字里带 Caches,位置也在缓存目录下,怎么看都是缓存,其实它是苹果神经引擎编译好的模型。CLI 早期真把它当缓存清了,用户那边所有用到识别功能的 App 全挂,一直到重启才好。从那以后我养成一个习惯,看到名字里带 cache 的目录,先在心里过三个问题:谁写的、重启之后谁会去读它、万一删错了怎么找回来,有一个答不上来我就不动它。

这类工具好不好,我不太看能清多少,主要看删之前让不让你看清楚。

Mole 清理的时候是先扫描,逐项列出来,每一项显示具体是什么、在哪、占多少,拿不准的默认不勾选,确认完再删,删的时候优先进废纸篓,后悔了还能找回来。扫描和清理全程在本机完成,文件和结果都不会上传。

代价是慢,多了一步确认,赶时间的时候会嫌它啰嗦,但我还是想让它宁可漏删也不误删。

卸载走的是同一套逻辑,选中一个 App,Mole 会把它散在系统各处的东西一起翻出来,逐项标上路径和大小,上面这张图里 Claude 本体只有 781MB,~/Library/Application Support/claude 却有 7.67 GB,真正占空间的从来不是应用包本身。登录项和后台服务也放在同一页,不用再去系统设置里一个个找。

举个例子,macOS 系统更新下载下来的安装包,也就是 /macOS Install Data 那个目录,经常十几个 G,看着是完美的清理目标。但系统可能还等着用它把更新装完,删早了机器就起不来。所以它在 Mole 里是默认不勾选的审阅项,前面叠了三道门,系统里有更新等着装就整行隐藏,安装包最近 14 天里动过就隐藏,安装相关进程还在运行也隐藏,哪个信号读不出来,就当它有风险,直接不显示。

真到执行删除那一刻,root 权限的脚本还会把这几项检查重新跑一遍,不通过就非零退出,不会出现「报告说清了 12G 其实一个字节没动」这种事。

我自己判断一款清理工具好不好,有个很土的办法。装同一个厂商的两款产品,只卸掉其中一款,看它会不会把两款共用的 Application Support 父目录或者 group 容器也列进去。列进去了,说明它是按名字匹配的,不是按归属判断。归属都说不清的工具,我不太敢让它批量删东西。

来源:少数派 原文