一个由 AI 代理驱动的 macOS 开发者缓存清理 Skill。
在 Codex / Trae / Claude 等 AI 代理里用自然语言说一句「清理我的开发缓存」,代理读取本仓库的 SKILL.md 后调用内置 Python 脚本,自动完成扫描、分级与可恢复的清理。
🌐 在线主页:yancongya.github.io/mac-dev-cleanup
mac-dev-cleanup 是一个 AI Skill(不是独立 App):
SKILL.md—— 给 AI 代理读取的技能清单(代理据此知道何时、如何调用本 Skill);scripts/mac_dev_cleanup.py—— Skill 真正执行的清理引擎(纯 Python 标准库,零运行时依赖);scripts/web_server.py+dashboard_template.html—— 本地 Web 控制台(读状态、改配置、触发扫描);- 本
README.md—— 给人看的仓库说明。
README.md 与 SKILL.md 不冲突:前者面向人类浏览 GitHub,后者面向 AI 代理运行 Skill,两者职责完全不同、可共存。
仓库中的
dashboard.html是构建产物(dashboard_template.html的副本),不入库、由本地scan生成;.gitignore同时排除含本机数据的config_data.js/dashboard_data.js/config.json/state.json。
步骤 0(推荐)· 一键下载并使用:把下面这句直接复制给 AI 代理,它会自动完成「克隆仓库 → 安装到 skills 目录 → 跑只读扫描做安装验证」的完整链路:
请帮我把这个 skill 快速下载并安装使用:把仓库 https://github.com/yancongya/mac-dev-cleanup.git 克隆到 ~/.codex/skills/mac-dev-cleanup,然后运行 scan 做一次只读扫描作为安装验证,告诉我能清理多少空间、有哪些需要我确认的项目。如果缺少 Python 或权限不足,也请说明。
如需手动操作:
-
手动安装 Skill(终端执行,把仓库放到代理的 skills 目录,下例以 Codex 为例):
git clone https://github.com/yancongya/mac-dev-cleanup.git ~/.codex/skills/mac-dev-cleanup若用 SkillDo 统一管理多个 Skill,推荐只保留一份物理目录
~/.skillshub/mac-dev-cleanup,其余工具的 skills 目录一律用软链指过去——多份真副本会各自漂移,导致不同代理读到不同版本的代码。 -
调用 Skill(安装后,在 AI 代理对话里直接说,可整句复制粘贴):
用 mac-dev-cleanup 这个 skill 帮我扫描并清理开发缓存:先只做只读扫描,再列出可清理项让我确认后再执行。
- 识别 25 类清理目标:全局/应用缓存与日志、项目生成物、日志与临时文件、测试产物、截图、大目录/大文件、闲置依赖与闲置模型、微信缓存与过期媒体、白名单应用的缓存与用户数据、Xcode 产物(DerivedData/DeviceSupport/Archives/模拟器)、开发缓存(Homebrew/pnpm/go/mise,Gradle 守护进程感知)、AI 工具缓存(含 Claude Code 旧版本,只留最新)、孤儿残留(反向扫描易失性目录 + 双向标识符匹配)、浏览器 profile 缓存(Chromium 系 + Firefox,Service Worker 站点数据永不碰)、安装包(DMG/PKG/ISO/XIP + ZIP 载荷校验)、iOS 设备备份(只读报告)…
- 重复文件查找(
dupes子命令):大小 → 64KB 头哈希 → 全量 SHA-256 四级渐进;硬链接不算重复;报告性质(选哪份保留是人决策),看板报告面板展示浪费总量 - 三级风险模型:
safe/aggressive/manual(manual永不自动删除,仅报告待确认) - 配置化应用白名单:把
~/Library/Application Support/<App>下可安全回收的缓存(如录屏中断残档、Crashpad、日志)纳入扫描,用户数据(如截图历史)只报告不删;应用常驻时自动跳过,退出后重跑即回收 - Stale 项目识别:以源码 mtime + 最后 git commit 判定(默认 90 天)
- 可恢复清理:真实清理「先进废纸篓」,写入操作清单,可一键还原——绝不使用裸
rm - 清理后自动回收:
--apply完成后自动清空废纸篓(后台 osascript + 10 分钟轮询)并核验回收;df未回补时按 SKILL.md 的对照实验判断,而不是重复删除 - 容器只报告、不盲删:Docker / OrbStack 的镜像与卷只做列表与人工确认(
docker container prune会连服务容器一起删) - 项目内结构整理(Project hygiene):除磁盘级缓存外,还能整理单个项目——清空格目录、删 AI IDE 残留(
.agents/.claude/.opencode/.superpowers/.workflow/.DS_Store/*.bak)、把散落的migrate_*/fix_*/test_*/init_*脚本归位到scripts//tests/、合并冗余文档。全程 Git 感知(git mv/git rm),不碰源码与数据库 - 本地 Web 控制台:六视图(概览 = 纯只读仪表盘 / 清理 = 唯一执行域含整模式与按勾选两种范式 + 重复文件 / 系统 = 应用卸载 + 启动项 + TM 快照 / 还原 = 操作与执行统一时间线 + 废纸篓 / 计划任务 / 设置含工具自检);服务/FDA 权限降级由顶部全局横幅统一提示;端口解析顺序
--port→MDC_PORT→config.json: dashboard_port(默认 8766,避让常被占用的 8765) - 系统废纸篓管理:
~/.Trash全量清单(隔离区单列、保持可恢复);清空需逐字确认串EMPTY TRASH+ API token 双重门禁,默认保留隔离区 - TM 本地快照管理:列表 + 单条删除;
com.apple.os.update-*系统更新回滚点代码级拒绝删除,重启装完更新即自动释放 - 启动项只读报告:第三方 LaunchAgents/LaunchDaemons 解析(com.apple.* 过滤);刻意不接删除,启停归
launchctl - TCC 优雅降级:
~/.Trash与MobileSync是 macOS 权限保护目录——无权限时 API 返回available: false/ 类别缺席并给出授权指引,绝不中断扫描或报 500 - 零运行时依赖:纯 Python 标准库
下文用 <skill-dir> 指代安装目录(经典布局为 ~/.codex/skills/mac-dev-cleanup,SkillDo 布局为 ~/.skillshub/mac-dev-cleanup):
python3 <skill-dir>/scripts/mac_dev_cleanup.py scan # 只读扫描
python3 <skill-dir>/scripts/mac_dev_cleanup.py clean-safe # 干跑(只报告)
python3 <skill-dir>/scripts/mac_dev_cleanup.py clean-safe --apply # 真清理(进废纸篓)
python3 <skill-dir>/scripts/mac_dev_cleanup.py dupes # 重复文件报告(只读)
python3 <skill-dir>/scripts/mac_dev_cleanup.py --show-config # 查看当前配置
python3 <skill-dir>/scripts/web_server.py --port 8766 # 启动本地 Web 控制台完整说明见 SKILL.md、CHANGELOG.md 与在线文档。
清理采用「Trash-first」策略:真实删除会先把文件移入 ~/.Trash/mac-dev-cleanup/<操作ID>/ 并写入操作清单,便于一键还原。完成后 Skill 会自动清空废纸篓释放空间(后台 osascript + 10 分钟轮询),并核验回收。
若 df 未及时回血,先用对照实验区分「记账失灵」与「清理没生效」:往 /tmp 写一个 512M 文件看 df 是否变化,再删掉看是否回补——写降删不回补是记账问题(多见于有待装系统更新),写降删也回补则说明腾出的块被其它进程占用,两种都不该重复删。切勿因 df 未变就误判清理失败(验证用 df -h ~,而非 df /)。详见 SKILL.md 的「APFS snapshots」章节。
另注意:~/.Trash、~/Library/Application Support/MobileSync 与 Safari 缓存受 macOS TCC 保护,crontab 读写也跟随同一权限。若 Web 控制台的「系统废纸篓」显示不可用、或扫描报告里没有 iOS 备份类别,需给服务进程授予「完全磁盘访问权限」,要点如下(2026-09-29 实证):
- 授权对象是解释器实体,不是
/usr/bin/python3——那只是个 shim,exec 后进程实体变成 CLT 解释器,TCC 只认后者:/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/python3.9 - 该文件在 FDA 添加对话框里是灰色的(Launch Services 把版本号
.9误判为扩展名),「前往文件夹」对隐藏路径/软链也不跳转。唯一可靠方法:在 Finder 按Cmd+Shift+G进入上述目录,把python3.9文件直接拖到「完全磁盘访问权限」列表上,再打开开关。切勿经 Yoink/Dropover 等拖拽暂存工具——会给文件打隔离标记,导致服务进程被 SIGKILL。 - 授权后
launchctl kickstart -k gui/$(id -u)/com.yancongya.mac-dev-cleanup重启服务生效。 - Xcode CLT 升级后授权静默失效(TCC 按实体路径 + ad-hoc 签名匹配),症状是废纸篓/crontab 又变「未授权」——重复一次拖拽即可。
- 已授权但控制台仍显示「不可用」?先排查孤儿进程,别急着重新授权:若 Finder 拖拽授权已完成、
launchctl kickstart -k重启后/api/trash仍available:false,很可能是 端口 8766 被一个 pre-FDA 的旧进程占着——该进程在授权前就启动、从未获得 FDA 资格,launchd 按 KeepAlive 反复拉新实例全因Address already in use崩溃(err.log crash-loop),dashboard 始终连到这个无授权的老进程(2026-09-30 实案:P0 bug 的bootout曾让进程脱离 launchd 追踪却未死,长期占端口)。诊断:lsof -nP -iTCP:8766 -sTCP:LISTEN看 PID 启动时间;若早于授权时刻就是它。kill <pid>终止后launchctl kickstart -k gui/$(id -u)/com.yancongya.mac-dev-cleanup让 launchd 干净重建单实例即可,无需重新授权。 - 不要在受限的 agent / IDE 终端里直接
stat ~/.Trash验证 FDA:那种环境自身没有 FDA(ps/launchctl list都被拒),它的 python 子进程必然PermissionError,会造成「授权失效」的假阴性。正确验证:在已授权的服务上launchctl kickstart -k之后,用浏览器或真实 Terminal(非 agent 子 shell)访问GET /api/trash,看system.available字段——true即授权生效。