02 · 总体架构与依赖边界
Mole 的关键边界不是 Shell 与 Go,而是“路由、策略、采集、交互、副作用”五种职责之间的依赖方向。
仓库分层
mole / mo CLI 路由与版本 ├── bin/*.sh 命令入口:clean / uninstall / optimize / ... │ ├── lib/clean/* 清理目标发现 │ ├── lib/uninstall/* 应用身份、残留与批处理 │ ├── lib/optimize/* 诊断、任务目录、结果模型 │ └── lib/core/* 安全、权限、超时、日志、UI ├── cmd/analyze 磁盘分析 TUI / JSON │ └── internal/analyze/* 扫描、缓存、删除、视图 ├── cmd/status 系统状态 TUI / JSON / NDJSON │ └── internal/status/* 采集、评分、历史、视图 ├── install.sh + lib/manage/* 安装、更新、移除 └── tests + scripts + workflows 质量与发布
bin/analyze.sh 与 bin/status.sh 只是适配器:找到安装目录里的 Go 二进制后直接 exec。这让顶层 mole 保持统一命令面,同时把 TUI 的生命周期交给 Go 进程。
依赖方向
Shell 公共运行时由 lib/core/common.sh 按固定顺序加载:基础变量与临时目录先建立,之后才是日志、超时、文件操作、UI、应用保护、Bundle 解析、安装收据与 sudo。
顺序很重要。例如文件操作要调用日志和保护函数;应用保护的数据表又应当与判断逻辑分离。若每个命令自行 source 一组文件,很容易形成“某命令少了一层保护”的隐性分叉。
两条执行路径
| 路径 | 生命周期 | 典型状态 |
|---|---|---|
| Shell 命令 | 一次性批处理 | 环境变量、数组、临时目录、操作日志 |
| Go TUI | 长生命周期事件循环 | Bubble Tea model、消息、缓存、采集历史 |
它们没有共享删除实现。Shell 的 mole_delete 需要处理 sudo、AppleScript、root staging;Analyze 的 Go 删除器则优先使用 /usr/bin/trash,随后尝试同卷原子 rename,最后使用 Finder。两边共享的是产品契约:保护关键路径、默认可恢复、失败不偷偷永久删除。
控制面与数据面
- 控制面:
mole路由、菜单、命令参数、Optimize 目录、保护规则。 - 数据面:文件扫描、大小计算、系统指标采集、删除执行。
- 证据面:预览、结果汇总、operations/deletions 日志、JSON 输出。
把证据面单独看待很重要。对于维护工具,“实际做了什么”必须能被机器读取或事后解释,不能只靠一行绿色成功提示。
构建产物
Makefile 将两个 Go 程序构建为本地 analyze-go / status-go;发布时用 CGO_ENABLED=0 生成 darwin-amd64 与 darwin-arm64。Shell 文件和 Go 二进制由安装器一起装入配置目录,再由薄适配器寻找。
关键源码索引
lib/core/common.sh:公共模块装配顺序。bin/analyze.sh:Go Analyze 适配器。bin/status.sh:Go Status 适配器。Makefile:跨架构构建目标。
下一章从用户输入开始,追踪顶层路由如何决定 source、exec 与交互菜单。