开源 · macOS · Rust + Tauri 2

看得清楚,清得放心

Tidy 是 Mole 的开源 macOS 桌面端。清理、卸载、优化、磁盘分析都先把完整候选清单摆在你面前;你勾了什么,它就只删什么——工程上做不到多删一个文件。

macOS 11+Universal(Intel 与 Apple 芯片)中文 / English版本 0.1.0 · 17 MB

0.1.0 是第一个公开版本。安装包已用 Developer ID 签名并通过 Apple 公证,打开时不会出现「无法验证开发者」。应用会检查自身更新,也会发送匿名使用统计——两者都能在设置里关掉,采集了什么见隐私说明历史版本

Tidy 清理页的起始界面,中央写着「准备扫描可清理空间」,副标题为「缓存 · 日志 · 开发残留,全程可预览」,下方是「开始扫描」按钮;顶部导航依次为清理、软件、优化、分析、状态
清理页的起点。产品自己就把承诺写在这里:「全程可预览」。截图取自 0.1.0 本地构建,项目尚未发布安装包。

全工程只有一处能删除文件

clippy.toml 通过 disallowed-methods 禁用了 mole-core::sink 以外所有 std::fs::remove_*。整个 workspace 里只有 sink 里存在一处 #[allow],新增删除行为必须走 DeletionPlan

来源:desktop/clippy.toml、crates/mole-core/src/sink.rs

预览和执行是同一批候选

plan_* 命令扫描后把预览存进 PlanStore,execute_plan 只接受 (plan_id, 你勾选的子集)。确认之后不会重新扫描,界面没有办法执行未曾预览过的内容。

来源:src-tauri 两阶段 IPC 契约

删除走废纸篓,历史与 CLI 兼容

删除通过 NSFileManager 移入废纸篓。operations.logdeletions.log 的写入格式由 golden test 钉住,与 Mole CLI 逐字节一致,mo history 能同时读到两边的记录。

来源:crates/mole-macos、crates/mole-core 日志写入器

产品界面

删之前,先把清单摆出来

卸载页列出这台机器上的每一个应用与它占的空间;展开任意一行,就能看到这个应用留下的全部文件。你勾选的那一份,就是最终会被移入废纸篓的全部——确认之后不会重新扫描。

Tidy 软件页的卸载列表,共 131 个应用按体积从大到小排序:Xcode 4.25GB、IntelliJ IDEA 4.22GB、GoLand 3.61GB、MounRiver Studio 2 3.24GB、Android Studio 2.65GB 等,每行右侧各有一个展开箭头和一个勾选框
卸载页:131 个已安装应用按体积排序。每行的展开箭头会列出这个应用的 App Support、缓存、日志、偏好设置、容器等全部残留;勾选框决定实际执行范围。截图取自 0.1.0 本地构建。

典型流程

四件事,每一件都能停在预览这一步

清出被缓存吃掉的空间

以前:知道 ~/Library/Caches 很大,但不敢整个删。

  1. 点「开始扫描」
  2. Tidy按 App 缓存、日志、开发工具、AI 工具、浏览器、设计工具、通讯工具、安装包分组列出每一项与体积,正在运行的应用单独标出并说明关掉后还能再清多少
  3. 结果勾选后移入废纸篓,界面给出本次释放的容量;记录同时写进 operations.log

把一个应用真正卸干净

以前:拖进废纸篓,Application Support、容器、LaunchAgent 全留着。

  1. 在「软件」里选中要卸载的应用
  2. Tidy按 App、App Support、缓存、日志、偏好设置、Launch Agents、HTTP 存储、WebKit、Saved State、容器分类列出每个残留文件;系统组件与「必须使用官方卸载器」的应用会被挡下并说明原因
  3. 结果逐项复核后一次移除,仍然是废纸篓,可恢复

看清哪些软件该更新

以前:逐个打开应用点「检查更新」。

  1. 打开「软件 → 更新」
  2. Tidy按 Homebrew / App Store / Sparkle / Electron / 官网 分组。Homebrew 在桌面端只读,只给出可复制的终端命令;其它来源直接打开应用自己的更新器或准确的 App Store 商品页
  3. 结果探测失败的来源单独列在「来源诊断」里——有失败探测时不会被写成「全部已是最新」
Tidy 软件页的更新列表:顶部是可展开的「来源诊断 (9)」,下方「可在 Tidy 内更新 28 个」依次列出 Apifox(Electron)、BetterDisplay(Sparkle)、Bitwarden(App Store)等,每行显示当前版本到新版本以及「忽略更新」与「更新」两个操作
更新页:来源在每一行标出,探测失败的来源单独收进顶部的「来源诊断 (9)」,不会被算进「全部已是最新」。截图取自 0.1.0 本地构建。

跑一轮有边界的系统维护

以前:从网上抄一串不知道会改什么的命令。

  1. 点一次「优化」
  2. Tidy执行启动速度、系统数据库、网络与搜索、系统维护四类任务;不安装软件包、不修改隐私权限、不删除个人文档
  3. 结果每个任务给出完成 / 跳过 / 失败,跳过时写明原因:unchanged、apps_running、probe_failed、requires_admin、skipped

五个模块

导航上就这五项,位置不会变

清理

按来源分组的可回收空间。

  • App 缓存、日志、开发工具
  • AI 工具、浏览器、设计工具、通讯工具
  • 残留的 dmg / pkg / xip 安装包
系统级缓存与日志需要特权助手,当前以 requires_admin 拒绝

软件

卸载、更新、登录项三个子页。

  • 按类别展开每个残留文件
  • 更新按来源分组,附来源诊断
  • 登录项与后台服务清单
Homebrew 在桌面端只读;系统级登录项只读

优化

一次有边界的维护任务集合。

  • 启动速度:QuickLook、字体、Launch Services
  • 系统数据库:可压缩的数据库与通知历史
  • 网络与搜索:DNS、路由缓存、Spotlight
不安装软件包、不重置隐私权限、不删除个人文档

分析

整盘或当前目录的空间树图。

  • 点击文件夹逐层下钻
  • 扫描可随时取消
  • 可直接把选中的目录移入废纸篓
取消的扫描会明确标注「结果不完整」,不会当成完整结论

状态

这台 Mac 现在在忙什么。

  • CPU、内存、磁盘、网络、电池、GPU
  • 风扇转速(无风扇机型显示为被动散热)
  • 进程明细:线程、打开文件、磁盘 IO、监听端口
监听公网接口的进程会被明确提示

设置

语言、白名单、历史记录。

  • 中文 / English,默认跟随系统
  • 白名单:永远不被列为候选的路径
  • 操作与删除历史
共享状态位于 ~/.config/mole,历史位于 ~/Library/Logs/mole

安全边界

所有破坏性操作都走同一条漏斗

这不是文案约定,而是代码结构:每个会删东西的功能都构造 DeletionPlan,最终只能经由唯一的 sink 执行。白名单检查、会话标记、日志、进度上报因此不可能在不同功能之间跑偏。

  • 1扫描枚举候选,不改动任何文件
  • 2预览逐项列出路径、类别、体积,以及被挡下的原因
  • 3确认候选数量与字节数在预览和确认之间保持不变
  • 4执行只接受你勾选的子集,中途可协作式取消
  • 5结果完成、被拒绝、失败分开呈现;部分成功不会渲染成全部成功

数据留在本机

共享状态在 ~/.config/mole,操作与删除历史在 ~/Library/Logs/mole。仓库里没有任何分析、埋点或崩溃上报代码。窗口的 CSP 是 default-src 'self'

只有检查更新时联网

更新扫描会访问 Apple 的 bundle ID 查询接口、应用自己的 Sparkle feed、GitHub release API,并读取本机 Homebrew 的输出。一次扫描 15 分钟后过期,更新按钮只携带后端签发的不透明 ID。

保护名单在编译期生成

app_protection_data.shbuild.rs 解析成 Rust 常量,出现任何无法识别的行会直接让构建失败(fail-closed)。名单的 DATA_SHA256 显示在「关于」一栏,可以核对。

拿不准就拒绝

特权助手的 in-helper 二次校验与「祖先目录可变则拒绝」逻辑已经在仓库里,但 SMAppService/XPC 传输尚未发布,因此系统范围的操作会直接以 requires_admin 拒绝,不会退回到 shell 提权。

获取方式

直接下载,或者自己编译一份

多数人下载 DMG 就够了。想亲自确认它到底删什么的话,源码在 github.com/rambocode/tidydesktop/ 目录,需要 Rust stable 与 Node ≥ 20。

git clone https://github.com/rambocode/tidy.git
cd tidy/desktop

# 后端测试
cargo test --workspace
cargo clippy --workspace -- -D warnings

# 运行桌面应用
cd ui && npm install && npx tauri dev

已知情况:mole-coredangerous_paths_corpus_all_rejected 测试依赖父仓库的对抗性用例文件;在只包含 desktop/ 的检出里这一个测试会失败,属于预期。

常见问题

购买与上手之前会问的

现在能直接下载安装包吗?

能。下载 0.1.0 的 DMG(17 MB,Universal,同时支持 Intel 与 Apple 芯片,需要 macOS 11 或更新版本)。安装包用 Developer ID 签名并通过 Apple 公证,首次打开不会被拦。应用也会自己检查更新。

删错了能找回来吗?

用户范围的删除全部通过 NSFileManager 移入废纸篓,可以从废纸篓恢复。系统范围的操作目前不会执行,而是以 requires_admin 拒绝,所以不存在「悄悄删掉系统文件」的路径。每次操作都会写入 ~/Library/Logs/mole

它会上传我的文件或使用数据吗?

仓库里没有分析、埋点或崩溃上报代码,窗口 CSP 限定为 default-src 'self'。唯一的对外请求发生在你主动检查软件更新时:Apple 的 bundle ID 查询接口、应用自己的 Sparkle feed、GitHub release API。

和 Mole 命令行是什么关系?

Tidy 是 Mole 的桌面端,安全层是 CLI 那一套逻辑的 Rust 移植。对外产品名用 Tidy,内部 crate 名、兼容事件和共享日志仍然叫 Mole。operations.logdeletions.log 逐字节兼容,mo history 能同时读到两边的记录。

为什么有些项目点不动?

界面会写明原因:unchanged(目标不存在或已经是健康状态)、apps_running(先关掉对应应用)、probe_failed(无法证明这一步是安全的)、requires_admin(需要尚未发布的特权助手)、skipped(在白名单里或被其它安全条件挡下)。被禁用的控件会保留标签并说明原因,而不是只把它变灰。

支持 Windows 或 Linux 吗?

目前不支持。适配层是 mole-macos,依赖 NSFileManager 废纸篓与 macOS 的特权助手模型,暂时没有其它平台的实现。

反馈

遇到拒绝原因看不懂的地方,直接开 issue

先看清楚,再决定删什么

源码、安全边界、日志格式全部公开可查。