关于 macos-cleaner
macOS Cleaner 面向需要诊断磁盘占用并释放已获批准空间的用户,同时保护数据和服务。它将只读检查、清理计划、授权操作与独立验证分阶段处理。
主要功能
- 01只读诊断磁盘与服务状态
- 02针对具体目标提供清理指引
- 03检查授权与操作影响
- 04禁止使用 Docker prune 命令
- 05清理后验证空间与服务状态
- 06根据历史读数分析增长来源
适用场景
- 01调查可用空间异常减少
- 02评估 Docker 或应用缓存占用
- 03规划删除已确认可弃用的文件
- 04检查释放空间及服务健康状况
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ daymade/ claude-code-skills --skill macos-cleaner安装后在 Claude Code 中输入/macos-cleaner确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/apfs-shared-blocks.mdapple_content_caching.mdbatch-selection.mdchromium_code_sign_clones.mdcleanup_targets.mddocker_analysis.mdgrowth_attribution.mdmole_integration.mdproving-redundancy-before-deletion.mdreport_templates.mdsafety_rules.mdscripts/_apfs_core.py_apfs_native.pyanalyze_caches.pyanalyze_code_sign_clones.pyanalyze_dev_env.pyanalyze_large_files.pyapfs_cow.pybatch_budget.pycheck_gate_plan.pycleanup_report.pyfind_app_remnants.pysafe_delete.pystream_accounting.pytests/fixtures/corpus/known-bad-original.mdknown-good-arm1.mdknown-good-round2-plan.mdknown-good-round2-table.mdknown-good-zai.mdtests/fixtures/review-probes-r3/r3-01_gate.md详细介绍
macOS 清理工具
诊断磁盘空间紧张的实际来源,只回收已批准的空间,并证明清理未损坏用户数据或共驻服务。
入口路由
选择能够回答请求的最窄路径:
| 用户信号 | 路由 |
|---|---|
| 相同的非活动本地文件必须保留所有路径并可离线访问 | 阅读 references/apfs-shared-blocks.md;仅使用获授权的明确配对、原生 APFS 检查和随附的防护执行器 |
Apple Content Caching、AssetCacheManagerUtil、CacheUsed、ActualCacheUsed、iCloud 缓存或“Caching needs more space” | 在探查或提出命令之前,完整阅读 references/apple_content_caching.md |
| Docker、OrbStack、镜像、容器或卷 | 阅读 references/docker_analysis.md;检查每个对象,绝不使用 prune 系列命令 |
| Docker 构建缓存 | 使用 docker builder du 测量;此技能会报告该缓存,但不会删除,因为 Docker 提供的是按类别清理的控制,而非针对单条记录意图的控制 |
Chrome、ChromeDriver、Playwright、Codex Computer Use、Edge 或 Chromium 存在较大的 *.code_sign_clone 目录 | 完整阅读 references/chromium_code_sign_clones.md;使用随附的分析器区分活跃、非活跃和未知的精确子项,绝不将 du 结果等同于实际释放空间 |
| 已有可疑对象是某个具名缓存、目录、应用或服务 | 先检查该目标,并阅读 references/cleanup_targets.md 中对应的语义;不要从主目录或整盘扫描开始 |
用户询问最近什么内容一直在增长或占满磁盘、两次读数之间可用空间减少,或存在较早的扫描导出文件(GrandPerspective 文本导出、保存的 du 输出) | 阅读 references/growth_attribution.md;用差异表作答,表格行应注明写入方,而非按大小排名 |
| 来源确实未知 | 使用下文的通用分析工作流;Mole 是可选项,不是通用的第一步 |
用户指定的范围排除项优先于所有通用扫描建议。若用户排除了个人目录、凭据、数据库、应用状态或无关服务,则不要检查这些内容。
安全与授权约定
-
将观察与变更分开。 先完成只读诊断。在此阶段不要删除内容、停止服务、编辑设置、安装或升级工具,也不要运行可能改变状态的清理预览。
-
确认确切目标。 在远程 Mac 上,先记录当前主机身份,再开展任何其他工作。绝不能根据 IP、旧 PID、目录名称或先前的报告推断机器身份。
-
先规划,再征求许可。 在进行任何状态变更之前,列出每条命令、其变更内容、预期释放的物理空间、影响、可恢复性和后置条件。然后,如果用户要求仅规划阶段,就停止。
-
先处理已有授权,再征求许可。 如果用户提供了确切的确认短语,就必须要求其提供该短语。否则,在明确清理指令所述的范围和条件内重复使用该指令。对于“清理所有已证实安全的内容”,应将确切目标与经核实的可丢弃内容、非活动状态、已保留的源文件/状态及恢复成本绑定,然后执行这些目标,无需再次征求许可。内容未知、独一无二的工作、活动资源或更广的范围都需要单独决定;同事关于未使用的报告只能作为证据,不能作为授权。
-
使用精确且受支持的控制方式,并先检查已知缺陷。 优先使用应用支持的缓存管理命令或确切的对象 ID。“官方”和“精确”都不能证明安全,因此在首次运行受支持的控制命令之前,必须针对已安装版本检查该确切命令的已知问题:在工具的问题跟踪器中搜索命令名称,并检查其更新日志,确认是否有修复已在比已安装版本更新的版本中发布。存在与当前版本相关且尚未解决缺陷的命令,不属于此技能的受支持控制方式——应像下一条规则中的类别级命令一样对待,并升级到已包含修复的版本,或改用确切路径替代方案。如果没有受支持的控制方式,只有在核实目录所有者、确认应用已停止或目录处于非活动状态、说明重建/重新下载的影响并获得批准后,才能删除确切的应用专属缓存目录。绝不能针对宽泛的缓存根目录或活动应用状态。
-
绝不使用 Docker prune 系列命令。 包括 image、container、volume、system、builder 和 buildx prune。类别级删除无法表达用户对单个对象的意图。
-
避免宽泛且具有破坏性的 shell 命令形式。 不要建议或执行宽泛的
rm -rf或通配符删除。对于已确切获批的普通文件,优先使用 Finder 废纸篓。随附的旧版辅助工具会永久删除内容,且只有下文记录的有限防护措施;绝不能将其视为等同于废纸篓。 -
保留有价值的状态。 绝不能仅为增加报告的节省空间而针对用户文档、凭据、SSH 材料、活动数据库、应用配置或运行中服务的状态。删除任何文件前,请阅读
references/safety_rules.md。 -
执行须遵循用户授权。 如果用户只要求分析或希望自行运行命令,就应将命令交由用户执行。如果已有的明确授权涵盖经核实的目标,就执行确切的获批操作并进行验证。编写或启用无人值守的定期删除逻辑之前,需要另行获得批准。
-
在受影响的目标上快速失败。 命令出现意外的非零退出状态、后置条件不匹配、目标异常或依赖项变更时,应停止该操作。先解读已记录的探测状态,例如
lsof以退出码 1 结束且输出为空,再判断其是否失败。保留未解决的状态,并继续处理相互独立且已获授权的目标。可选备份失败时,应先重新评估是否需要备份,再考虑更改传输工具或重试。 -
承诺任何删除都会释放物理空间之前,先说明具体机制,并以创建该内容的命令为依据,不要猜测。
df与名义上的du总量及实际可回收空间之间存在差额,说明某种候选机制正在起作用,而最有力的证据是创建该文件夹的原始命令,因为只有复制命令本身能决定空间语义。先从会话历史中查找该命令,再提出假设;根据文件夹名称或大小作出的推断不算机制。只有在找不到任何命令时,才能将差额标记为unknown——不要用听起来最合理的机制替代可以举证的机制。 按du的报告结果和删除时释放的空间来区分这些机制(均于 2026-09-19 测量,源数据为 1 GiB,并控制了数据漂移):创建方式 du标称值删除副本释放的空间 特征 cp(裸命令)/cp -a完整计量,每个路径分别计数 全部 独立 inode,独立 extent cp -c/cp -cR(clonefile)完整计量,每个路径分别计数 ≈0 不同 inode, nlink=1,共享 extentln/cp -l(硬链接)只计一次——同级副本显示 0≈0 相同 inode, nlink=2本地 APFS 快照 完整 在快照被精简前约为 0 tmutil listlocalsnapshots /这张表旨在揭穿两个误区。clonefile 和硬链接两行的
du结果相反,但删除效果相同——两者释放的空间都约为 0,因此“删除后没有释放空间”无法区分两者,而du可以:硬链接的同级副本只计一次(或显示为0),clonefile 副本则完整计量。另一个误区是,用错复制命令进行校准毫无证明力:有两次把 98 GiB 的差值归因于错误机制,原因是探测时用了裸cp,而文件夹实际是用cp -cR创建的。删除任何内容之前,先用与创建时相同的标志运行探测。clonefile 值得特别注意,因为它是常见情况——macOS 的cp在使用-c时默认采用该机制,而且为交付内容或工具包复制的目录通常都会带有它。
阶段约定
每次清理都使用以下状态机:
- 观察——只读。 记录身份信息、磁盘基线、疑似子系统的状态和配置、物理分配情况,以及关键服务的健康状况。 1b. 在无法避免时,授权有状态检查。 如果需要创建临时容器、拉取镜像、挂载卷或写入快照才能获取更深入的证据,则先完成仅限元数据的观察,列出确切的检查命令及其副作用,并另行获得批准。检查授权不等于清理授权。
- 计划——不作修改。 先通过第 2 阶段准入门槛,然后说明发现、命令、影响、恢复方式、预期释放量和成功标准。如果缺少授权,或用户要求本阶段只提供计划,则在确认门槛处停止。
- 执行——仅限已批准的范围。 操作前立即重新读取实时状态,然后逐条运行已批准的命令,并检查其退出状态和后置条件。
- 验证——独立回读。 再次测量磁盘空间和子系统状态,重新检查受保护的服务,并观察足够长的时间,以发现是否立即重新占满。
缺少授权时,应在阶段 2 和阶段 3 之间停止;打印计划并不会产生授权。如果已有指示涵盖已核实的目标及其后果,则通过门槛后继续执行,不必再次询问同一事项的许可。
创建备份前先选择删除依据
- 保护独特的源代码修改、本地 Git 状态、凭据、数据库和用户记录。目录名称、年龄或
lsof结果为空,单独来看都不能证明内容可以删除。备份无法让缺乏依据的删除变得合理。 - 对于非活动且可重建的依赖目录、构建缓存或已退役的打包测试 App,保留其源代码/锁文件或当前安装,并说明重建成本。除非用户明确要求保留该制品,否则不要归档、复制、提取或哈希第二份完整副本。发现手动编辑、无法获取的私有软件包或嵌入的独特状态,会改变分类;想象中的可能性不会。
- 将“安全”视为不丢失独特成果、不影响正在进行的使用,并且了解恢复成本。不要以可逐字节恢复所有可处置制品来替代这一条件。对于用户明确选择丢弃的已退役二进制文件,不要要求其具备精确的可重现性。
- 对每个保留候选项,说明具体的阻碍事实和最小的后续检查。在任务范围内完成这些检查;只说“情况不确定”或释放了少量空间,都不能算完成获准的清理,已知候选项仍未检查时尤其如此。
- 进行任何必要的备份/复制/提取前,先在目标主机上运行现有的计划检查器,并使用
--copy-budget <manifest.json>。按未压缩源数据的大小,计算所有同时保留的归档、提取后的目录、验证副本和重试产生的部分文件;不要假设压缩或 APFS 共享能节省空间。每个阶段开始前都要重新检查目标端的可用空间;如果无法维持声明的预留空间,就停止该次复制。继续独立的清理操作。清单约定和限制请参见references/safety_rules.md。
阶段 1:只读诊断
确定基线
至少采集:
/bin/date "+%F %T %Z %z"
/usr/sbin/scutil --get ComputerName
/usr/sbin/scutil --get LocalHostName
/usr/bin/sw_vers
/usr/sbin/sysctl kern.boottime vm.swapusage
/bin/df -k /System/Volumes/Data
/bin/df -h /System/Volumes/Data
使用 df -k 进行计算,使用 df -h 生成易读报告。扩展名、标签或旧报告只能作为线索,须以实时命令确认。
准确复制用户提供的可用空间或容量目标。只读清点无需先确定目标:报告当前数值,并在获准的读取范围内找出占用空间最大的内容。不要为了询问清理目标而延迟诊断。没有明确目标的清理不能声称已达到用户的容量目标;应报告测得的释放量和剩余候选项。
第一阶段保持只读。暂时不要运行 scripts/cleanup_report.py:它会创建本地状态目录和快照文件。改为在报告中保留命令输出。对于远程目标,始终在该主机上直接运行 df 命令;本地辅助工具不得误测控制器 Mac。
先检查指定的可疑对象,再进行大范围扫描
- 查询该子系统自身的状态和设置。
- 仅在权限和用户范围允许时,针对确切的数据路径使用有界的
du测量物理分配情况。 - 区分逻辑内容大小、稀疏文件的表观大小、可清除空间和物理分配字节数。
- 对于 APFS 克隆,将
du标注为按路径统计或名义值,而非物理值:共享范围可能被归入每个路径,因此实际释放量在删除并通过df读取确认前仍然未知。 - 对于疑似持续增长的日志,在两个或更多时间点记录精确文件大小。单个大文件或较新的修改时间都不能证明日志持续增长。
- 对于用户标记为关键的共置服务,记录当前进程、监听端口、启动机制及受支持的健康检查探针。在每个检查点重新解析 PID。
如果仅清理已知的可疑对象就能达到用户的可用空间目标,不要以防万一为由扫描无关的个人或开发目录。
未知来源的常规分析
首先,将占用空间调查与清理项选择分开。在每个获准根目录中,获取一份浅层大小明细(例如 du -x -k -d 1 "<approved-root>");包括隐藏子项,将无法访问的路径记录为未知,并复用已完成的测量结果。即使最大的占用项必须保留,也要将其列出。先深入调查最大的未解释分支,再花时间检查较小的缓存。除非状态发生变化,否则不要重新扫描已完成检查的同级目录。这是只读的空间测量,不代表获准读取文件内容或删除任何内容;下文关于获准路径的约定仍适用于包含内容的根目录。
然后,按顺序执行以下能够对相关占用项进行分类的最少步骤。对于清理目标,只有在候选项有可靠的具体操作方案,且预期实际释放空间有充分依据时,才能将其计入目标。原始分配总量、缓存逻辑大小、Docker 共享层、移入废纸篓的内容以及未经验证的“潜在节省”均不满足停止条件。对于仅盘点的请求,当已说明获准根目录中最大的占用项和覆盖范围缺口时即可停止;未经授权,不得删除。
不要因为侧重实际空间可信度的排名而掩盖用户可见的最大占用项。当按名义大小或路径统计的候选项大于推荐操作时,应同时显示两个数字,并解释其实际释放空间为何不确定。按有据可依的实际释放空间、安全性和工作量排序;将名义大小单独列为一栏,而不要默默地将其视为零或完全可回收。
| 顺序 / 信号 | 只读操作 | 停止或继续 |
|---|---|---|
| 1. 始终执行 | 记录设备身份并运行 df -k/-h;盘点用户排除项 | 目标不匹配时停止 |
2. 缓存/日志空间压力,且 ~/Library/Caches、~/Library/Logs 和 XDG 开发缓存均获准读取 | uv run scripts/analyze_caches.py --user-only --include-dev | 当测得的候选项足以达到目标时停止 |
| 3. 存在开发者工具,且脚本的固定范围获准读取 | uv run scripts/analyze_dev_env.py 会读取 Docker/包管理器,以及现有的 ~/Projects、~/workspace、~/dev、~/src 和 ~/code 根目录 | 将 Docker/OrbStack 的发现结果转至专用参考文档;任何固定根目录不在范围内时,跳过此辅助脚本 |
| 4. 可能存在未安装应用的残留,且其固定根目录获准读取 | uv run scripts/find_app_remnants.py 会读取 /Applications、~/Applications 和四个文档所述的 ~/Library 应用状态根目录 | 将每项结果都视为候选项,而非放弃使用的证明;该范围未获准时跳过 |
| 5. 某个包含内容的路径已获明确授权 | uv run scripts/analyze_large_files.py --threshold 100MB --path "<approved-path>" | 未获准具体路径时,不得以 ~、Downloads、Documents 或数据卷根目录代替 |
| 6. 有限检查后仍有未知项,且用户明确批准 Mole 固定的广泛扫描根目录 | 阅读 references/mole_integration.md,并通过 TTY 使用 mo analyze | Mole 不接受任意路径范围;批准范围窄于其文档所列根目录时,跳过 |
<approved-path> 是用户指定的确切路径,或用户在获知其范围后明确接受的路径。如果不存在这样的路径,则跳过大文件和重复内容扫描,说明此证据分支未获授权,并继续收集不读取文件内容的证据。只读阶段不得安装或升级 Mole,除非用户另行授权此更改。
Mole 的分析器会扫描一组固定路径,包括主目录、应用数据、系统库、应用和卷。在结果中进行导航,并不会使底层扫描变成按路径限定范围。如果未获准读取这一广泛范围,则不要运行 Mole;应根据已收集的有限证据停止,或在计划中询问缺少的扫描授权。
对于经明确批准的重复文件调查,请阅读 references/cleanup_targets.md 中的“可选重复文件”部分。该流程为只读,且绝不使用自动删除选项。
大型数据文件夹不是缓存——提议删除它需要一条证据链,而不是按大小排名。 当发现流程找到一个较大的项目资产/媒体/数据集目录(不是缓存,也不是应用残留)时,不要仅凭大小就将其列入操作集:提出任何建议之前,请阅读 references/proving-redundancy-before-deletion.md。交付内容是证据表;无法证明的条目(纯粹依赖手动判断使用情况)应交由用户处理,绝不能含糊带过。
如果将发现工作分派给多个子 Agent,每个子 Agent 只能返回候选项和测量结果——分类、接受与否以及提议都必须在运行第 2 阶段入口门槛的会话中完成。子 Agent 的清单是分类表的输入,绝不能直接作为计划。
Docker 和 OrbStack
报告 Docker 可回收空间之前,请阅读 references/docker_analysis.md。逐一列出每个镜像、容器和卷;检查引用关系及类似数据库的内容;使用实际稀疏文件占用空间,而不是表面大小。报告称某资源为 dangling,并不能证明其中的数据毫无价值。支持测量构建缓存,但有意将删除构建缓存排除在范围之外,因为可用的 Docker 控制操作属于 prune 系列。
第 2 阶段:报告并确认授权
第 2 阶段入口门槛
开始或扩展长批次之前,请阅读 references/batch-selection.md。
使用 scripts/batch_budget.py 将试点测量结果、剩余可回收空间上限和耗时与实际可用空间缺口联系起来;项目数量不代表容量目标已达成。
一次真实的 2026-09-19 运行严格遵循了第 1 阶段的流程,却仍然产出了三个糟糕的计划:它将默认保留的缓存(npm _cacache、Playwright 浏览器、Homebrew)作为“低风险组合”提出,因为相关规则写在 references/cleanup_targets.md 中——而发现流程从未打开过这个文件;它根据 --help 中的一行说明和大小比例,将 uv cache prune 判定为零影响,却从未核实其语义或已安装版本;由于没有设定可用空间目标,它还把 2 GB 的项目排在一个 91 GB 候选项之前。早已存在于此技能中的规则本可以避免这三种情况——但它们位于流程从未打开过的参考资料中,因此实际上并不算规则。文字清单只比它所概述的参考资料好一点:对这道入口门槛初稿的独立审查发现了 13 个阻塞性缺陷,其中最根本的问题是,这道门槛本身没有机械化执行机制。因此,第 4 步是一个脚本,而不是一句承诺——运行它,否则计划就不存在。
-
说明要报告的目标。 对于清理目标,请使用用户给出的准确数值。若用户未提供目标,则交付空间占用清单或按优先级排序的决策列表;不要自行设定容量目标,也不要声称已经达成目标。
-
打开
references/cleanup_targets.md,并将发现流程产生的每个候选项分类到下表中,然后写入文件(第 4 步会解析该文件):目标 名义大小 物理空间置信度 类别 适用规则(原文引用) 预计实际释放空间 + 依据 恢复成本 结论 确切目标:路径、服务设置(例如 AssetCacheManagerUtil或 plist 键),或受支持的控制项(例如chrome://settings/clearBrowserData)du 输出 路径统计(Phase 1 对 APFS 共享或名义 du 的标记)/ 感知稀疏文件 / 引擎报告(子系统自身的统计,例如 Docker system df)/ 未知——绝不能将名义大小填作释放空间PRESERVE / PROPOSABLE / REBUILDABLE / USER-DATA / USER-DECISION 引自 cleanup_targets.md、该路径专属参考文档或本技能自身的 SKILL.md;检查器会对照整个资料包验证每条引用,并打印各文件的来源,因此仅在 SKILL.md 中出现的引用也会保留;“未找到规则”本身就是一项发现估算值及其推导方式;允许填“未知” 重新下载/重建成本,或不适用 在操作集内 / 不在操作集内 / 由用户解锁(引用相关指示) - PRESERVE ——
cleanup_targets.md中默认保留表的每一行(在此步骤中打开,并在表格中引用——步骤 4 会验证引用,因此伪造的引用会验证失败)。不纳入操作集,除非 (a) 有经核实的从未使用证据,或 (b) 用户明确指定要清理该目标并了解相关成本。接受你说明的成本不属于 (b):必须由用户亲自指定目标。 - PROPOSABLE —— 有经核实的从未使用证据(已失效的项目、用户明确陈述、产物检查)。大小比例不构成证据:“缓存中有 586 个环境,而有 28 个项目虚拟环境”并不能证明其余 558 个环境的情况。
- REBUILDABLE —— 不在默认保留表中,且有受支持的管理命令或可低成本重建(Homebrew、pip);在行中说明恢复成本。
- USER-DATA —— 绝不纳入操作集;报告位置,不提供命令。
- USER-DECISION —— 由用户对自身工作流或所有权情况的了解来决定;应询问,不要提议。未被任何参考文档覆盖的目标(“未找到规则”)也归入此类:计划要求在提出任何操作建议前先询问。
如果任何参考文档都未涵盖某个目标,请注明“未找到规则”,并将其归类为 USER-DECISION——不要牵强附会地套用不相关规则。
- PRESERVE ——
-
应用门槛规则。 第 4 步的检查器会机械地强制执行每条规则——这正是它们成为规则而非提醒的原因:
- 操作集恰好包含标记为“in action set”的行,以及标记为“unlocked by user”且引用了用户指示的行。任何会改变状态的命令都不得指定表中未列出的目标。PRESERVE 行只能凭借从未使用过的证据或用户的明确指示(第 2 步)进入操作集。
- 计划应优先处理操作集中预期释放物理空间最多的行——除非表格注明另一行是用户可见的热点或瓶颈(即磁盘压力实际针对的对象),并说明了理由。任何其他优先行都会导致此门槛不通过;这属于只挑小鱼,而非谨慎。切勿仅按名义大小排序:名义大小不等于释放量;对于共享区段候选项,只有删除并读取
df的回读结果后才能确定释放量(第 2 步的标签)。 - 每条破坏性命令都必须记录:所属工具的已安装版本(对于应用控制或服务命令,记录所属应用或服务的版本);语义来源(工具自身的帮助信息或文档——如果唯一可用的来源是本技能的转述,须如实说明,并通过低成本方式对照实际工具进行核验);以及对于按类别执行的命令——作用范围是整个对象类别,无法逐个对象选择;本技能现有术语为 prune-family——已知问题检查。
uv cache prune、npm cache clean、brew cleanup --prune和 Docker prune 系列命令按定义都属于按类别执行的命令。 - 本技能声明为不允许的命令(
uv cache prune、npm cache clean、Docker prune 系列命令)即使符合所有其他规则,也不得出现在操作集中——不论大小,也不论版本。npm cache clean被列入其中,是因为它会彻底清空默认保留的_cacache。只有用户明确指示执行该确切命令,才能将其加入;并且它必须作为用户指定的操作在第 3 阶段执行,不能作为提议。 - 操作集为空也是合理结果:提供按优先级排列的决策清单(包含 PRESERVE 和 USER-DECISION 行及其解锁成本和证据),并询问用户要解锁哪些项。操作集为空但附有决策清单,检查即可通过;编造行或将 PRESERVE 降级以填满操作集则不行。
-
先将计划写入文件,再运行检查器,然后再发送:
uv run scripts/check_gate_plan.py --table <gate-table.md> --plan <plan.md>退出码为 0 是必要条件,但不能证明未识别的命令已经过检查。请阅读已检查的命令数量以及每条覆盖范围诊断:如果拟议的删除操作检查的命令数为 0,则该操作未经检查。请使用检查器可识别的精确形式,或在执行前独立确认该命令的目标覆盖范围和语义;不要把“coverage incomplete”旁边的 PASS 当作批准。检查器会核验表格分类、规则原文引用、可识别的破坏性命令目标、操作类别和解锁规则、默认保留保护、按类别执行的排除项、释放量排序以及工具核验。它能识别
uv run和使用相对或绝对脚本路径调用safe_delete.py的 Python 命令,并会逐一检查每个字面目标;无法解析的批处理文件和 Shell 展开会导致覆盖检查失败。运行失败时会指出违反的规则——请修正计划,不要削弱检查器。 在让一个真实的 18 个目标计划以退出码 0 结束的过程中,检查器可靠捕获了五种失败情形——这五项都应在计划侧修正,而不是修改检查器:- 路径格式不匹配(
target_coverage):表格必须包含命令所用的同一个完整绝对路径;~/简写形式的行与使用/Users/…的命令不匹配。 - 一行包含两个目标:列出两个配对目标的行无法解析——每个目标单独占一行。
- 发布列中的“du nominal”会被视为名义数值并遭拒;应说明预期释放量的推导方式,或填写
unknown。 - 表格单元格中的单行 osascript 会被拆成管道符分隔的片段,命令匹配器无法重新拼合——应将规范的多行 osascript 放在计划的代码块中,而不是表格行里。
- 在说明文字中提及命令(例如引言句提到 osascript)会被解析为命令起始处,却没有匹配的行——说明文字中不要出现命令名称,表格行应以路径开头,而不是标签(以
OrbStack开头的行会失败)。
- 路径格式不匹配(
报告观测到的值,而非推断出的属性。长篇报告请使用 references/report_templates.md 中的布局,并为每个拟议操作填写以下字段:
| 字段 | 必需内容 |
|---|---|
| 当前状态 | 时间戳、目标身份、磁盘已用空间/可用空间/容量,以及子系统状态 |
| 证据 | 命令和观测到的值;说明该数值是逻辑值还是物理值 |
| 精确命令 | 会改变状态的命令,以及精确的目标或对象 ID |
| 变更 | 命令修改或删除的内容 |
| 可恢复性 | 可逆命令、从废纸篓恢复、从备份还原,或只能重新下载 |
| 预期释放空间 | 物理空间估算值、单位和假设 |
| 服务影响 | 用户可见的影响及受保护服务的不变条件 |
| 后置条件 | 判定操作成功前必须满足的值 |
按后果分类发现项,而不是按数字看起来有多诱人来分类:
- 可重建缓存: 删除只会丢失本地副本,但应说明重新下载或重建的成本。默认情况下,不得提议清理可重建内容:
references/cleanup_targets.md中的默认保留表(已在 Phase 2 准入门槛处打开并引用)决定哪些目标应保留;在有证据证明从未使用过或用户明确指示之前,这些目标不得纳入操作集。 - 需要用户决定: 价值取决于用户的工作流程或所有权知识。
- 保留: 用户数据、凭据、数据库状态、当前配置,或角色不明确的任何内容。
不要仅仅因为软件可以重新生成缓存,就称其“绝对安全”。重新生成所需的时间、带宽、身份验证和离线可用性都是实际成本。
Phase 3:执行已确认的计划
在第一条改变状态的命令即将执行前:
- 重新确认目标身份和当前磁盘状态。
- 重新查询对象或子系统状态;实时状态发生变化时,清理计划即失效。
- 重新检查受保护服务的健康状态。
- 将已批准的命令和精确目标集与即将运行的命令进行比较。任何范围更广或有所不同的目标集都需要重新批准。如果单独保留的项目变为非活动状态,且仍被明确排除,并且已批准的目标集哈希仍匹配,则不会使计划失效。 让批准项和排除项始终与原始清单关联。“删除这些;其余保留”只批准这些目标;“继续查找”则恢复只读发现。如果某些已批准路径已不存在,请停止批处理,并报告原始数量、剩余数量和缺失数量。只有在证明较小集合属于该清单的子集,且身份、内容和后果均未改变后,才能继续处理;现有授权可涵盖这一经核实的剩余集合。同一路径上新生成的替代项属于已改变的目标。不要用同伴报告的未操作情况代替用户批准,也不要将本次运行前已不存在的路径报告为已删除。旧版辅助工具遇到目标缺失时仍会停止;再次调用前,请先协调处理计划。
如果已批准的计划包含创建本地前后对比报告文件,请现在(即批准后、首次清理命令前)捕获清理前快照:
uv run scripts/cleanup_report.py --snapshot before
这会在 ~/.macos-cleaner 下写入文件,因此请在计划中列出该路径。此操作为可选项,且仅适用于本地目标;直接读取 df -k/-h 仍是事实依据。切勿在控制器 Mac 上运行此操作来代替测量远程目标。
每次只运行一条会改变状态的命令。读取结果后,再发送下一条命令。每条命令运行后,都要执行能够区分成功与部分成功的后置条件检查。
对于确切的普通文件(不是用户数据、应用状态、数据库或受保护路径),在用户确认确切路径后,优先使用 Finder 废纸篓进行可恢复移除:
/usr/bin/osascript \
-e 'on run argv' \
-e 'tell application "Finder" to delete (POSIX file (item 1 of argv))' \
-e 'end run' -- "<exact-path>"
移到废纸篓通常不会立即释放物理空间,只有清空废纸篓后才会释放;请在计划中说明这一点。
远程和无头目标:Finder 通道需要 Automation 授权,而通过 ssh 发起的 AppleEvents 在未获授权时会挂起。 2026-10-07 在一台无头工作机上实测:通过 ssh 会话驱动上述 osascript 废纸篓移动操作时,会无限期阻塞——已处理 9 个目标,第 1 个目标仍然存在,废纸篓也没有变化,甚至无害的 Finder 探测(count of items)也始终没有返回。没有可捕获的错误;唯一的迹象就是毫无响应。通过 ssh 使用 Finder 通道前,请先运行有时限的探测;若探测挂起,应视为通道已关闭,而不是 Finder 运行缓慢。原生 macOS 没有 timeout(1),因此请直接在 AppleScript 中设置时限:
/usr/bin/osascript \
-e 'with timeout of 1 second' \
-e 'tell application "Finder" to count of items of trash' \
-e 'end timeout'
同一卷宗上的备用方案是隔离移动,而非移入废纸篓:将每个确切的已批准目标用 mv 移至同一卷宗上的目录(<approved-dir>/_quarantine-<date>/),并在旁边写入一份 MANIFEST(包含原始路径、大小、时间戳)——mv 回移恢复操作需要原始路径。它与废纸篓具有相同的安全属性——同一卷宗上的 mv 只修改元数据、完全可恢复,且在另行批准永久清理前不会释放空间——并且无需 Automation 授权。与废纸篓操作一样,必须将两个阶段严格分开:隔离移动和之后的永久删除需要分别批准,计划必须注明隔离位置和 MANIFEST。Phase 2 计划检查器会专门识别隔离命令格式(以 mv 开头,可容忍命令表单元格中的反引号;第一个参数必须是带引号或类似路径的词元,且命令中包含 _quarantine- 标记),并像处理 osascript 废纸篓格式那样,将每条命令绑定到对应表格行;普通 mv、git mv、sudo mv、非隔离重命名,或仅仅以“mv”一词开头的说明句都不会被识别,因此隔离命令仍须在表格中明确写出每个目标。
scripts/safe_delete.py 是一个旧版永久删除辅助工具,带有交互式提示和有限的系统/凭据拒绝列表。它不会将文件移到废纸篓,不会检查所有用户数据根目录,不会检测打开的文件,也不会独立证明回收的字节数。传入多个路径时,它会切换为一次批量确认,接受 all、索引列表或 none——通过管道传入 yes 会输入 y,批量解析器会将其判定为无效选择,随后取消整个批次,不删除任何内容(2026-10-23 测得);预先获准的批次应回答 all。仅当精确的非用户数据目标及不可逆删除已获明确批准时才使用:
uv run scripts/safe_delete.py <exact-path> [<exact-path> ...]
不要将此辅助工具用于用户文档、由应用管理的缓存(例如 Apple Content Caching)、数据库、凭据,或任何用途不确定的目标。
以下两种范围严格限定的 Finder 废纸篓操作仍可使用,且不会放宽上述排除项:
- 对于没有已验证的受支持管理控制方式的确切非活动应用缓存,请遵循
references/cleanup_targets.md中指定的缓存发现/使用中协议,说明重建成本,并就该确切缓存路径取得明确批准。 - 对于确切获批用户数据根目录中的重复文件,首先列出每组重复文件的大小/哈希值及所有路径。用户必须指定要保留的副本和要移除的每个副本。仅将这些已确认的文件移到 Finder 废纸篓;绝不要使用永久删除辅助工具、自动重复项选择标志、
all、通配符或目录级目标。确认源路径中的文件已移到废纸篓,并说明只有在另行检查并清空废纸篓后,物理空间才会释放。
第 4 阶段:验证并观察
验证必须涵盖获批计划的所有条款:
- 重新读取
df -k和df -h;分别报告测量时间窗口内的净变化与按路径核算的已移除大小。检查时间戳和kern.boottime:重启、交换空间释放或并发写入都会使该窗口成为混合窗口,不能证明全部变化都是由删除造成的。报告未解释的剩余量,不要强行归因到某个目录。 - 重新查询已清理子系统的激活状态、配置和物理用量。
- 重新解析每个受保护服务的 PID、监听器、启动机制和健康探测结果。磁盘健康不代表服务仍正常运行。报告未满足的约束并停止受影响的操作;清理磁盘并未授权重启服务、终止其他会话或修复无关应用。
- 当 APFS 统计可能滞后或源数据可能回填时,以有限间隔进行观察。记录每次观察的时间戳和值。
- 如果未达到可用空间目标,停止所有删除操作。开始第二轮只读分析,并按测得的物理分配量对剩余来源排序。
仅知道命令退出代码时,绝不要报告“已修复”。清理成功既要求达到预期状态,也要求受保护的约束仍然满足。使用第 4 阶段结果字段和示例案例,区分紧急恢复与尚未完成的容量调查,并在工作已有解释时直接结束,避免额外扫描。
对于由辅助工具捕获了删除前快照的本地目标,请使用以下命令生成对比结果:
uv run scripts/cleanup_report.py --snapshot after --compare
资源
references/batch-selection.md和scripts/batch_budget.py— 根据提供的容量和试运行证据,选择有界的下一批;未知上限仍保持未知。references/apfs-shared-blocks.md和scripts/apfs_cow.py— 通过受保护的 APFS 克隆、固定回滚、逐项释放锁以及精确的剩余清单,保留精确的非活动本地路径。scripts/stream_accounting.py— 根据提供的原生观测值,计算内部完整克隆分配上限;它不是探测工具,也不测量物理空间释放量。
仅加载与当前任务相关的分支:
references/apple_content_caching.md— Apple 内容缓存诊断、单位解读、受支持的远程控制、确认计划和清理后验证。references/chromium_code_sign_clones.md— Chrome/Chromium/Edge 代码签名克隆的语义、名义值与物理值报告、精确的非活动目标清单、清理验证和复发预防。references/cleanup_targets.md— 缓存、日志、应用、开发者、大文件和 Time Machine 目标的语义。references/proving-redundancy-before-deletion.md— 提议删除任何大型项目资源/媒体/数据集目录之前,先加载;按大小排序并非证据。references/growth_attribution.md— 关于“最近增长了什么”的问题:查找并校准基线导出、未扫描陷阱、哪个文件时间戳能回答“何时新增”、将按路径统计的增量与df(交换空间、快照、短暂副本)进行核对,以及识别写入者。references/docker_analysis.md— Docker 和 OrbStack 的逐对象分析、数据库卷防护以及重新填充的根因诊断。references/mole_integration.md— 交互式 Mole 分析和预览的 TTY 工作流。references/report_templates.md— 通用报告和 Docker 报告的长篇模板。references/safety_rules.md— 禁止访问的路径、确认、恢复和文件删除安全检查。scripts/analyze_caches.py— 有界缓存清单;保留unknown测量值和诊断信息,将不完整的小计视为已知下限;将退出码 1 解读为测量不完整或开发者路径尚未解决,而非占用为零。scripts/check_gate_plan.py— 第 2 阶段入场门槛检查器:解析分类表和计划,核对规则引用与参考资料是否一致、破坏性命令是否覆盖目标(无法识别的命令形式也会计数并报告)、操作集合的类别和解锁规则、默认保留降级交叉检查、类别范围排除项、首行排序规则以及工具验证。计划发送前必须返回退出码 0。其命令白名单存在明确限制:不在列表中的形式会报告为无法识别,而不会被静默忽略。scripts/analyze_code_sign_clones.py— 只读的当前用户代码签名克隆清单;获得批准后,可重新验证精确候选 SHA 并写入不覆盖现有内容的批次清单。scripts/find_app_remnants.py— 应用残留候选项;读取其固定的 Applications 和~/Library根路径,因此必须先要求批准该范围。scripts/analyze_large_files.py— 在已批准路径内查找大文件。scripts/analyze_dev_env.py— Docker/包管理器清单,以及固定常用项目根目录的.git大小;必须先要求批准完整读取范围。scripts/safe_delete.py— 用于精确且已批准的非用户数据目标的旧版受保护永久删除工具;它不是废纸篓或恢复工具。scripts/cleanup_report.py— 默认针对/System/Volumes/Data的本地目标清理前后报告,可通过--volume显式指定其他卷。
以下情况请勿使用此技能
- 目标系统是 Windows 或 Linux。
- 请求的操作需要禁用 SIP 或绕过 macOS 保护机制。
- 用户要求在没有可审计范围和确认关卡的情况下静默或自动删除内容。
- 任务仅涉及调整应用程序行为,不涉及磁盘空间诊断或恢复目标。