1实现原理 · 为什么它能做到
四步流水线:只读扫描 → agent 分级分析 → 生成交互式 HTML 报告 → 在对话里给结论先行摘要;扫描与报告分离,中间产物是一份 JSON。
对 macOS 做一次只读存储分析,产出交互式 HTML 报告。流程:扫描 → 分析分级 → 生成网页 → 打开。
扫描器全部只读:只跑 df/du/diskutil/stat/ls 与 os.scandir,绝不写盘;脚本 docstring 与 SKILL.md 铁律双重声明。
STRICTLY READ-ONLY: only sizes/lists/reads metadata. Never creates, moves, or deletes anything.
扫描器自动识别系统(sys.platform)走两套目标目录:macOS 扫 home/library/caches/containers/app_support/applications/downloads/dev_caches 并用 du 算大小;Windows 扫 user_profile/appdata/temp/downloads/program_files 并用 os.scandir。
- **macOS**:扫 home、library、caches、containers、group_containers、app_support、applications、downloads、dev_caches,用 `du` 算大小。 - **Windows**:扫 user_profile、appdata_local、appdata_roaming、temp、downloads、program_files(_x86)、dev_caches,用 `os.scandir` 算大小;`system.disks` 含所有盘符。
分级是「清理决策清单」而非全盘点:只把存在「要不要动它」决策的项放进三灯,正常在用应用与系统文件落到蓝色「系统及其他」。
**三级分类 = 清理决策清单,不是全盘点。** 只把"存在'要不要动它'这个决策"的项放进三灯;日常在用的正常应用、操作系统本身、海量零碎小文件没有清理决策,不进三灯,它们落在磁盘条的蓝色"系统及其他"里。判定标准:
一键删除靠本地服务:server.py 起 127.0.0.1 + 随机端口 + 每会话随机 token,POST /action 才执行;静态模式(build_report.py)明确不给删除按钮。
- Bound to 127.0.0.1 only; every POST requires the session token; Host header
安全模型是三套白名单从严到宽:rm 仅绿灯 trash_paths;trash 允许绿灯+橙灯 trash_paths;open 另加橙灯 path 与红灯 app_paths,且全部 realpath 校验 + 必须在 $HOME 内。
**安全模型——三套白名单,权限从严到宽**:`rm` 只允许绿灯 `trash_paths`;`trash` 允许绿灯+橙灯 `trash_paths`(橙灯永远不能 rm);`open`(在文件管理器打开,非破坏性)允许上述全部 + 橙灯真实 `path`。所有请求 realpath 校验 + 必须在 $HOME 内 + token + Host 校验,每次点击浏览器先 confirm。
删除走系统回收站 API 而非直接 rm:macOS 用 osascript 让 Finder delete(失败回退 ~/.Trash 移动),Windows 用 SHFileOperationW + FOF_ALLOWUNDO。
script = 'tell application "Finder" to delete (POSIX file %s as alias)' % json.dumps(path)
橙灯只准移废纸篓(可逆),红灯干脆不给删除按钮、只给「在文件管理器打开」——这是对「有决策但不建议手删」的显式分级。
橙灯只准移废纸篓、可逆,绝不给"直接删除")。App 托管又无安全子路径的(Chrome/微信)只给打开按钮、不给 trash_paths。按钮下方会自动写明注意事项(打开只查看不删、移废纸篓可逆需清空才释放等);如果某项在文件管理器里是 App 内部格式、不方便手动挑选,给它一个 `open_note` 字段做客观说明(会显示在注意事项里)。**口吻要中性、像产品说明**:直接描述"这里是什么结构、为什么不好手动删、想精细操作该去哪",不要写成"我发现/提醒注意/看着像没视频"这种暴露开发者踩坑视角的话。 - 🔴 **谨慎清理(有决策但不建议手删)**:你可能想动、但建议别手删的具体项——重复安装的应用、想卸载的大应用、运行中应用的核心数据等。给"为什么不建议手删" + `indirect_release` 写**具体卸载步骤**(自带卸载器 / 启动台长按 / 右键移废纸篓 / AppCleaner 清残留 / App Store 可重装等,要可照做不是空话)。应用项给 `app_paths`(真实 `.app` 绝对路径数组)→ 网页出现「在文件管理器打开(去卸载)」按钮,定位到 App 让用户自己正规卸载。**红灯不给删除/卸载按钮**
报告是固定阅读流的交互式 HTML:磁盘总览(分段进度条)→ Top5 → 执行建议 → 三色可折叠卡片(命令一键复制)→ 长期优化建议,即「现状→诊断→处方→操作→预防」。
报告阅读流(固定顺序):磁盘总览卡片(容量 + 进度条 + 三色容量 pills + 系统信息,纯数据)→ 占用排行 Top5 → 执行建议 → 🟢🟡🔴 三级可折叠卡片(命令一键复制)→ 长期优化建议。
Windows 支持如实标注未实测,并要求首次跑核对路径、scandir 大小与回收站删除;多盘符已支持。
- **Windows**:代码已写(`scan.py` 的 `scan_windows`、`server.py` 的 `_trash_windows` 走 `SHFileOperationW`),但**未在真实 Windows 上实测**。
零第三方依赖:脚本只用 Python 3 标准库,macOS 自带 python3/du/diskutil/osascript,开箱即用。
- 全部脚本是 **Python 3 标准库**,零第三方依赖(不用 pip install)。
2核心能力
4风险提醒 风险提醒:蓝色 · 知晓即可
- 绿灯硬删除不可逆,且白名单源自 agent 判断 — rm 直接走 shutil.rmtree/os.remove;若 agent 把含用户数据的目录误判成绿灯写进 trash_paths,用户点一次即永久丢失。建议默认只用「移到废纸篓」,或先跑静态报告人工过一遍分级。
- 报告服务开着=本机多了一个删除接口 — 服务绑 127.0.0.1 且有 token,但若被端口转发/代理暴露或 token 与页面一起泄露,就等同于把白名单内的删除能力交出去;用完应立即 Ctrl+C 停服(skill 也提示按钮随即失效)。
- 删除命令展示需用户自己执行,存在误操作空间 — 绿灯项的命令是「可一键复制的清理命令」,用户自行粘贴执行时若改了路径或环境不同(如 Windows 用 python 而非 python3),可能删错目标;skill 建议谨慎用 rm 且必须指向明确缓存子目录。
- Windows 分支未经实测 — scan_windows 与 _trash_windows 未在真实 Windows 验证;首次使用需自行核对目录路径、os.scandir 大小与回收站删除是否正常。
- 扫描较慢、体量感知依赖系统命令 — du -sk 逐子目录在超大目录上耗时长(SKILL.md 提示「扫描较慢,耐心等」);读不到的目录标 denied,遗漏体量需在报告里说明,否则用户会误以为已全清。
5第二遍独立确认
- [ok] 扫描器确实只读 — scan.py 只用 os.scandir/os.listdir/du/df/diskutil 等读取与统计;无 open(...,"w")、无 shutil.rmtree/os.remove、无 mkdir;docstring 明写 STRICTLY READ-ONLY。
- [ok] 服务侧白名单构造与文档一致 — load() 中:green.trash_paths → rm/trash/open 三集合;yellow.trash_paths 只进 trash+open;yellow.path(存在时)只进 open;red.app_paths(存在时)只进 open——与 SKILL.md「三套白名单,权限从严到宽」逐条对应。
- [ok] 删除请求的多重校验 — do_POST 依次校验:Host ∈ {127.0.0.1, localhost}、token 相等、mode ∈ {rm,trash,open}、每个 path realpath 后必须在对应白名单、且必须在 HOME 或 /Applications 之下(删除类白名单不含 /Applications)。
- [ok] 回收站删除的实现 — macOS: osascript `tell application "Finder" to delete (POSIX file ...)`,失败回退 shutil.move 到 ~/.Trash;Windows: ctypes 调 SHFileOperationW,fFlags 含 FOF_ALLOWUNDO(进回收站)。
- [ok] 无公网请求 — 全目录 URL 扫描仅命中 http://127.0.0.1:%d/(服务自述地址);无 CDN、无遥测、无第三方 API。
- [ok] 无凭证读取 — API_KEY/token/secret 扫描:唯一 token 变量是 secrets.token_urlsafe(24) 生成的会话 token,非用户凭证;无 env 读取、无 keychain、无配置文件读取。
- [ok] 静态报告确实没有删除能力 — build_report.py 把 __DELETE_CONFIG__ 替换为 "null";模板里的 fetch(DELETE.endpoint, ...) 只有在服务模式下注入 token/endpoint 才可用(SKILL.md 的排障段落也这么说)。
- [ok] 零第三方依赖 — 三个脚本 import 仅 json/os/secrets/shutil/subprocess/sys/time/webbrowser/http.server/re/ctypes;无 requirements/pip 指令。
6结论
b8b3f5bde010e27b…48e8ba527f