macbroom 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. macbroom-1.1.0/LICENSE +21 -0
  2. macbroom-1.1.0/PKG-INFO +181 -0
  3. macbroom-1.1.0/README.md +131 -0
  4. macbroom-1.1.0/macbroom/__init__.py +5 -0
  5. macbroom-1.1.0/macbroom/__main__.py +8 -0
  6. macbroom-1.1.0/macbroom/cli.py +128 -0
  7. macbroom-1.1.0/macbroom/core/__init__.py +1 -0
  8. macbroom-1.1.0/macbroom/core/audit.py +61 -0
  9. macbroom-1.1.0/macbroom/core/fsutil.py +186 -0
  10. macbroom-1.1.0/macbroom/core/i18n.py +358 -0
  11. macbroom-1.1.0/macbroom/core/model.py +68 -0
  12. macbroom-1.1.0/macbroom/core/server.py +201 -0
  13. macbroom-1.1.0/macbroom/core/trash.py +88 -0
  14. macbroom-1.1.0/macbroom/doctor.py +127 -0
  15. macbroom-1.1.0/macbroom/scanners/__init__.py +66 -0
  16. macbroom-1.1.0/macbroom/scanners/app_leftovers.py +128 -0
  17. macbroom-1.1.0/macbroom/scanners/appindex.py +98 -0
  18. macbroom-1.1.0/macbroom/scanners/caches.py +197 -0
  19. macbroom-1.1.0/macbroom/scanners/duplicates.py +133 -0
  20. macbroom-1.1.0/macbroom/scanners/ios_dev.py +271 -0
  21. macbroom-1.1.0/macbroom/scanners/large_files.py +74 -0
  22. macbroom-1.1.0/macbroom/scanners/login_items.py +139 -0
  23. macbroom-1.1.0/macbroom/scanners/system_extras.py +217 -0
  24. macbroom-1.1.0/macbroom/web/app.js +868 -0
  25. macbroom-1.1.0/macbroom/web/index.html +102 -0
  26. macbroom-1.1.0/macbroom/web/style.css +362 -0
  27. macbroom-1.1.0/macbroom.egg-info/PKG-INFO +181 -0
  28. macbroom-1.1.0/macbroom.egg-info/SOURCES.txt +32 -0
  29. macbroom-1.1.0/macbroom.egg-info/dependency_links.txt +1 -0
  30. macbroom-1.1.0/macbroom.egg-info/entry_points.txt +2 -0
  31. macbroom-1.1.0/macbroom.egg-info/top_level.txt +1 -0
  32. macbroom-1.1.0/pyproject.toml +51 -0
  33. macbroom-1.1.0/setup.cfg +4 -0
  34. macbroom-1.1.0/tests/test_i18n.py +191 -0
macbroom-1.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 3Kiven
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: macbroom
3
+ Version: 1.1.0
4
+ Summary: Open-source macOS cleaner — free up disk space safely with a local web UI. Caches, app leftovers, large & duplicate files, dev junk.
5
+ Author: MacBroom contributors
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 3Kiven
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/mythkiven/MacBroom
29
+ Project-URL: Repository, https://github.com/mythkiven/MacBroom
30
+ Project-URL: Issues, https://github.com/mythkiven/MacBroom/issues
31
+ Keywords: macos,open-source,mac-cleaner,macos-cleaner,cleanmymac-alternative,cleanmymac,appcleaner,pearcleaner,disk-cleanup,disk-space,cache-cleaner,duplicate-finder,cleanup,uninstaller,developer-tools,xcode-cleaner,homebrew,privacy
32
+ Classifier: Development Status :: 5 - Production/Stable
33
+ Classifier: Environment :: Console
34
+ Classifier: Environment :: Web Environment
35
+ Classifier: Intended Audience :: End Users/Desktop
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Operating System :: MacOS :: MacOS X
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3.9
41
+ Classifier: Programming Language :: Python :: 3.10
42
+ Classifier: Programming Language :: Python :: 3.11
43
+ Classifier: Programming Language :: Python :: 3.12
44
+ Classifier: Programming Language :: Python :: 3.13
45
+ Classifier: Topic :: Utilities
46
+ Requires-Python: >=3.9
47
+ Description-Content-Type: text/markdown
48
+ License-File: LICENSE
49
+ Dynamic: license-file
50
+
51
+ <div align="center">
52
+
53
+ # 🧹 MacBroom
54
+
55
+ **Open-source macOS cleaner — free up disk space safely**
56
+ <br>**开源 macOS 清理工具 — 安全、可视化地释放磁盘空间**
57
+
58
+ An **open-source CleanMyMac alternative**: scan reclaimable space → group it by app → tick and clean. Deletions go to the Trash by default and can be restored. Local-only, zero-dependency, no telemetry.
59
+
60
+ > 一个 **开源的 CleanMyMac 替代品**:扫描可释放空间 → 按软件分组 → 勾选一键清理。默认移入废纸篓、可还原;纯本地、零依赖、不联网。**完整中文文档见 [README.zh.md](./README.zh.md)。**
61
+
62
+ [简体中文](./README.zh.md) · English
63
+
64
+ [![CI](https://github.com/mythkiven/MacBroom/actions/workflows/ci.yml/badge.svg)](https://github.com/mythkiven/MacBroom/actions/workflows/ci.yml)
65
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
66
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
67
+ ![Platform: macOS](https://img.shields.io/badge/platform-macOS-lightgrey.svg)
68
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)
69
+
70
+ </div>
71
+
72
+ ![MacBroom main window](docs/screenshot.png)
73
+
74
+ ---
75
+
76
+ ## ✨ Features
77
+
78
+ - **Local only · zero dependencies**: pure Python 3 standard library, no network calls, no telemetry.
79
+ - **Safety first**: files go to the macOS Trash (not `rm`), restorable from Trash; system-critical paths (`/System`, Keychains, SSH keys, …) are hard-blocked.
80
+ - **Risk grading**: every item is tagged `safe / moderate / risky`. Risky items (personal data, irreversible actions) are **hidden by default** until you tick "Show risky items".
81
+ - **Explainable leftovers**: each suspected uninstall leftover shows *why* it was flagged (bundle id with no matching app) and can be **expanded to inspect the actual files** before you decide.
82
+ - **Confirm before delete (dry-run)**: the dialog lists every selected item with its path and reason, total count and reclaimable size; large totals (>10 GB) or risky selections get an extra warning.
83
+ - **Sort & drill-down**: sort results by size or name, expand any group or item to see what is inside.
84
+ - **Audit log**: every scan and deletion is written to `~/Library/Logs/MacBroom/macbroom.log` (override the directory with `MACBROOM_LOG_DIR`).
85
+ - **Grouped by app**: caches and the like are grouped per app; your selection is preserved across rescans.
86
+ - **Customizable**: toggle each scan category on/off; a persistent **exclusion list** for false positives; long scans are **cancelable**.
87
+ - **iCloud-aware**: detects iCloud-synced folders to avoid breaking cross-device sync.
88
+ - **Respects `CACHEDIR.TAG`**: standard cache markers are recognized so the right directories are treated as cache.
89
+ - **Covers popular apps**: beyond browser/dev caches, also Slack, Discord, VS Code, Microsoft Teams, Spotify, Steam, Telegram, Minecraft.
90
+ - **Login items check**: finds orphaned launch-at-login items pointing to deleted programs (the "background items" macOS warns about) and removes them.
91
+ - **CLI / scripting friendly**: `macbroom scan --json` prints a report right in the terminal for automation and CI.
92
+ - **`macbroom doctor`**: pre-flight checks for Python, Full Disk Access, log directory, and port availability before you scan.
93
+ - **No forced deletion**: items that can't be removed are listed with a copy-paste Terminal command for you to run.
94
+ - **Clean web UI**: collapsible groups, group-level select-all, live reclaimable-space totals.
95
+
96
+ ## 🔍 What it detects
97
+
98
+ | Category | Description |
99
+ |---|---|
100
+ | 🧹 **App Caches** | Rebuildable caches grouped by app (incl. npm/pip/Gradle/CocoaPods/Homebrew dev caches and Chrome/Edge/Brave/Arc/Firefox browser caches) |
101
+ | 👻 **App Leftovers** | Support files, containers, logs and preferences likely left by uninstalled apps (heuristic; review first) |
102
+ | 🐘 **Large Files** | Single files larger than 100 MB — find space-hungry videos / images / archives |
103
+ | 🛠️ **Dev Clutter** | Build products, caches, simulators and SDK temp dirs for iOS/Xcode, Android/Android Studio, HarmonyOS/DevEco Studio |
104
+ | 🧬 **Duplicate Files** | Byte-for-byte identical files (size → partial hash → full SHA-256), keeping the newest copy per group |
105
+ | 🚀 **Login / Startup Items** | Launch-at-login LaunchAgents / LaunchDaemons, focusing on orphaned entries pointing to deleted programs |
106
+ | ✨ **Other Cleanup** | Diagnostic reports, iOS device backups, Homebrew leftovers, Docker images, Time Machine local snapshots, scattered `node_modules`, mail attachment caches, old downloads |
107
+
108
+ ## 💡 Why MacBroom? — built from real cleaner failures
109
+
110
+ We read **hundreds of issues across popular open-source Mac cleaners** and designed MacBroom to *not* repeat their most painful, real, reported accidents:
111
+
112
+ | Real-world failure reported in other cleaners | How MacBroom avoids it by design |
113
+ |---|---|
114
+ | A cleaner deleted a user's **entire Chrome profile** — logins and bookmarks gone | We only target precise `Default/Cache` & `Code Cache` dirs — **never** the profile directory |
115
+ | **Apple Notes / Claude Code CLI deleted** as "leftovers" (matched by name, not identity) | Leftover detection matches **bundle id exactly**; each flagged item shows *why*, with an expandable file list to review before deleting |
116
+ | **Shell history wiped** (`~/.zsh_history`) as "junk" | We never scan or touch shell history |
117
+ | Cleanup **broke iCloud sync** (Desktop/Documents) | We **detect iCloud-synced paths**, mark them risky and hide them by default |
118
+ | Uninstall **misidentified unrelated files** (`~/Public`, printer configs, another app's data) | Bundle-id matching + risk grading + a persistent **exclusion list** to permanently skip false positives |
119
+ | **Wrong / negative free-space numbers** (sparse images counted by logical size) | Real on-disk usage via `st_blocks`, so sparse VM/disk images are not over-counted |
120
+ | **Untranslated or mistranslated UI** | Native-quality **English and Chinese** from day one, not machine-translated strings |
121
+ | **Simulator cleanup throwing errors** | iOS/Xcode simulators are cleaned through the official `xcrun simctl` interface, not by blindly deleting paths |
122
+ | **Long scans froze the app** with no way to stop | Every scan is **cancelable** mid-run |
123
+ | Orphaned **login items** left erroring in System Settings after uninstalls | Dedicated **Login Items scanner** flags startup entries pointing to deleted programs |
124
+
125
+ In short: **other cleaners delete first and apologize later. MacBroom is designed to be un-dangerous** — Trash-by-default, risky items hidden, dry-run confirmation that lists exactly what goes, and an audit log of everything it does.
126
+
127
+ ## 🚀 Usage
128
+
129
+ ### Option A: run from source (works today, no install)
130
+
131
+ ```bash
132
+ git clone https://github.com/mythkiven/MacBroom.git
133
+ cd MacBroom
134
+ ./run.sh # or: python -m macbroom
135
+ ```
136
+
137
+ ### Option B: pipx / pip
138
+
139
+ > Published to PyPI with the first tagged release. Until then, use Option A.
140
+
141
+ ```bash
142
+ pipx install macbroom # or: pip install macbroom
143
+ macbroom # starts and opens the browser
144
+ ```
145
+
146
+ The browser opens at `http://127.0.0.1:37700`. Click "Start Scan", then "Clean Selected".
147
+
148
+ ```bash
149
+ macbroom --port 40000 # custom port
150
+ macbroom --no-open # don't open the browser
151
+ ```
152
+
153
+ ### Option C: command-line report (headless / scripting)
154
+
155
+ ```bash
156
+ macbroom doctor # pre-flight: Python, FDA, port, log dir
157
+ macbroom scan # print per-category summary and total
158
+ macbroom scan --json # JSON output for scripts / CI
159
+ macbroom scan --category caches,login_items # scan specific categories only
160
+ ```
161
+
162
+ ## 🛡️ Security
163
+
164
+ See [SECURITY.md](./SECURITY.md) for the full security model and how to report vulnerabilities. In short: local-only, Trash-by-default, protected-path hard blocks, risk grading, audit log, loopback-only with Host validation + per-session CSRF token on the delete endpoint.
165
+
166
+ ## 🖥️ Compatibility
167
+
168
+ - Python 3.9+ (standard library only).
169
+ - macOS 12 (Monterey) through 15 (Sequoia) / 26 (Tahoe). On older systems, any missing path or command (e.g. `simctl runtime`, `tmutil thinlocalsnapshots`) is skipped automatically without affecting other categories.
170
+
171
+ ## 🤝 Contributing
172
+
173
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). MacBroom needs no third-party packages; run tests with:
174
+
175
+ ```bash
176
+ MACBROOM_LOG_DIR=/tmp/macbroom-test python -m unittest discover -s tests -v
177
+ ```
178
+
179
+ ## 📄 License
180
+
181
+ [MIT](./LICENSE)
@@ -0,0 +1,131 @@
1
+ <div align="center">
2
+
3
+ # 🧹 MacBroom
4
+
5
+ **Open-source macOS cleaner — free up disk space safely**
6
+ <br>**开源 macOS 清理工具 — 安全、可视化地释放磁盘空间**
7
+
8
+ An **open-source CleanMyMac alternative**: scan reclaimable space → group it by app → tick and clean. Deletions go to the Trash by default and can be restored. Local-only, zero-dependency, no telemetry.
9
+
10
+ > 一个 **开源的 CleanMyMac 替代品**:扫描可释放空间 → 按软件分组 → 勾选一键清理。默认移入废纸篓、可还原;纯本地、零依赖、不联网。**完整中文文档见 [README.zh.md](./README.zh.md)。**
11
+
12
+ [简体中文](./README.zh.md) · English
13
+
14
+ [![CI](https://github.com/mythkiven/MacBroom/actions/workflows/ci.yml/badge.svg)](https://github.com/mythkiven/MacBroom/actions/workflows/ci.yml)
15
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
16
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
17
+ ![Platform: macOS](https://img.shields.io/badge/platform-macOS-lightgrey.svg)
18
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)
19
+
20
+ </div>
21
+
22
+ ![MacBroom main window](docs/screenshot.png)
23
+
24
+ ---
25
+
26
+ ## ✨ Features
27
+
28
+ - **Local only · zero dependencies**: pure Python 3 standard library, no network calls, no telemetry.
29
+ - **Safety first**: files go to the macOS Trash (not `rm`), restorable from Trash; system-critical paths (`/System`, Keychains, SSH keys, …) are hard-blocked.
30
+ - **Risk grading**: every item is tagged `safe / moderate / risky`. Risky items (personal data, irreversible actions) are **hidden by default** until you tick "Show risky items".
31
+ - **Explainable leftovers**: each suspected uninstall leftover shows *why* it was flagged (bundle id with no matching app) and can be **expanded to inspect the actual files** before you decide.
32
+ - **Confirm before delete (dry-run)**: the dialog lists every selected item with its path and reason, total count and reclaimable size; large totals (>10 GB) or risky selections get an extra warning.
33
+ - **Sort & drill-down**: sort results by size or name, expand any group or item to see what is inside.
34
+ - **Audit log**: every scan and deletion is written to `~/Library/Logs/MacBroom/macbroom.log` (override the directory with `MACBROOM_LOG_DIR`).
35
+ - **Grouped by app**: caches and the like are grouped per app; your selection is preserved across rescans.
36
+ - **Customizable**: toggle each scan category on/off; a persistent **exclusion list** for false positives; long scans are **cancelable**.
37
+ - **iCloud-aware**: detects iCloud-synced folders to avoid breaking cross-device sync.
38
+ - **Respects `CACHEDIR.TAG`**: standard cache markers are recognized so the right directories are treated as cache.
39
+ - **Covers popular apps**: beyond browser/dev caches, also Slack, Discord, VS Code, Microsoft Teams, Spotify, Steam, Telegram, Minecraft.
40
+ - **Login items check**: finds orphaned launch-at-login items pointing to deleted programs (the "background items" macOS warns about) and removes them.
41
+ - **CLI / scripting friendly**: `macbroom scan --json` prints a report right in the terminal for automation and CI.
42
+ - **`macbroom doctor`**: pre-flight checks for Python, Full Disk Access, log directory, and port availability before you scan.
43
+ - **No forced deletion**: items that can't be removed are listed with a copy-paste Terminal command for you to run.
44
+ - **Clean web UI**: collapsible groups, group-level select-all, live reclaimable-space totals.
45
+
46
+ ## 🔍 What it detects
47
+
48
+ | Category | Description |
49
+ |---|---|
50
+ | 🧹 **App Caches** | Rebuildable caches grouped by app (incl. npm/pip/Gradle/CocoaPods/Homebrew dev caches and Chrome/Edge/Brave/Arc/Firefox browser caches) |
51
+ | 👻 **App Leftovers** | Support files, containers, logs and preferences likely left by uninstalled apps (heuristic; review first) |
52
+ | 🐘 **Large Files** | Single files larger than 100 MB — find space-hungry videos / images / archives |
53
+ | 🛠️ **Dev Clutter** | Build products, caches, simulators and SDK temp dirs for iOS/Xcode, Android/Android Studio, HarmonyOS/DevEco Studio |
54
+ | 🧬 **Duplicate Files** | Byte-for-byte identical files (size → partial hash → full SHA-256), keeping the newest copy per group |
55
+ | 🚀 **Login / Startup Items** | Launch-at-login LaunchAgents / LaunchDaemons, focusing on orphaned entries pointing to deleted programs |
56
+ | ✨ **Other Cleanup** | Diagnostic reports, iOS device backups, Homebrew leftovers, Docker images, Time Machine local snapshots, scattered `node_modules`, mail attachment caches, old downloads |
57
+
58
+ ## 💡 Why MacBroom? — built from real cleaner failures
59
+
60
+ We read **hundreds of issues across popular open-source Mac cleaners** and designed MacBroom to *not* repeat their most painful, real, reported accidents:
61
+
62
+ | Real-world failure reported in other cleaners | How MacBroom avoids it by design |
63
+ |---|---|
64
+ | A cleaner deleted a user's **entire Chrome profile** — logins and bookmarks gone | We only target precise `Default/Cache` & `Code Cache` dirs — **never** the profile directory |
65
+ | **Apple Notes / Claude Code CLI deleted** as "leftovers" (matched by name, not identity) | Leftover detection matches **bundle id exactly**; each flagged item shows *why*, with an expandable file list to review before deleting |
66
+ | **Shell history wiped** (`~/.zsh_history`) as "junk" | We never scan or touch shell history |
67
+ | Cleanup **broke iCloud sync** (Desktop/Documents) | We **detect iCloud-synced paths**, mark them risky and hide them by default |
68
+ | Uninstall **misidentified unrelated files** (`~/Public`, printer configs, another app's data) | Bundle-id matching + risk grading + a persistent **exclusion list** to permanently skip false positives |
69
+ | **Wrong / negative free-space numbers** (sparse images counted by logical size) | Real on-disk usage via `st_blocks`, so sparse VM/disk images are not over-counted |
70
+ | **Untranslated or mistranslated UI** | Native-quality **English and Chinese** from day one, not machine-translated strings |
71
+ | **Simulator cleanup throwing errors** | iOS/Xcode simulators are cleaned through the official `xcrun simctl` interface, not by blindly deleting paths |
72
+ | **Long scans froze the app** with no way to stop | Every scan is **cancelable** mid-run |
73
+ | Orphaned **login items** left erroring in System Settings after uninstalls | Dedicated **Login Items scanner** flags startup entries pointing to deleted programs |
74
+
75
+ In short: **other cleaners delete first and apologize later. MacBroom is designed to be un-dangerous** — Trash-by-default, risky items hidden, dry-run confirmation that lists exactly what goes, and an audit log of everything it does.
76
+
77
+ ## 🚀 Usage
78
+
79
+ ### Option A: run from source (works today, no install)
80
+
81
+ ```bash
82
+ git clone https://github.com/mythkiven/MacBroom.git
83
+ cd MacBroom
84
+ ./run.sh # or: python -m macbroom
85
+ ```
86
+
87
+ ### Option B: pipx / pip
88
+
89
+ > Published to PyPI with the first tagged release. Until then, use Option A.
90
+
91
+ ```bash
92
+ pipx install macbroom # or: pip install macbroom
93
+ macbroom # starts and opens the browser
94
+ ```
95
+
96
+ The browser opens at `http://127.0.0.1:37700`. Click "Start Scan", then "Clean Selected".
97
+
98
+ ```bash
99
+ macbroom --port 40000 # custom port
100
+ macbroom --no-open # don't open the browser
101
+ ```
102
+
103
+ ### Option C: command-line report (headless / scripting)
104
+
105
+ ```bash
106
+ macbroom doctor # pre-flight: Python, FDA, port, log dir
107
+ macbroom scan # print per-category summary and total
108
+ macbroom scan --json # JSON output for scripts / CI
109
+ macbroom scan --category caches,login_items # scan specific categories only
110
+ ```
111
+
112
+ ## 🛡️ Security
113
+
114
+ See [SECURITY.md](./SECURITY.md) for the full security model and how to report vulnerabilities. In short: local-only, Trash-by-default, protected-path hard blocks, risk grading, audit log, loopback-only with Host validation + per-session CSRF token on the delete endpoint.
115
+
116
+ ## 🖥️ Compatibility
117
+
118
+ - Python 3.9+ (standard library only).
119
+ - macOS 12 (Monterey) through 15 (Sequoia) / 26 (Tahoe). On older systems, any missing path or command (e.g. `simctl runtime`, `tmutil thinlocalsnapshots`) is skipped automatically without affecting other categories.
120
+
121
+ ## 🤝 Contributing
122
+
123
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). MacBroom needs no third-party packages; run tests with:
124
+
125
+ ```bash
126
+ MACBROOM_LOG_DIR=/tmp/macbroom-test python -m unittest discover -s tests -v
127
+ ```
128
+
129
+ ## 📄 License
130
+
131
+ [MIT](./LICENSE)
@@ -0,0 +1,5 @@
1
+ """MacBroom —— 本地、安全、可视化的 macOS 清理工具。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "1.1.0"
@@ -0,0 +1,8 @@
1
+ """支持 ``python -m macbroom`` 启动。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from macbroom.cli import main
6
+
7
+ if __name__ == "__main__":
8
+ main()
@@ -0,0 +1,128 @@
1
+ """MacBroom CLI —— 启动本地服务,或在终端直接扫描出报告。
2
+
3
+ 用法:
4
+ macbroom # 默认 127.0.0.1:37700,启动 Web UI 并打开浏览器
5
+ macbroom --port 40000
6
+ macbroom --no-open # 不自动打开浏览器
7
+ python -m macbroom # 等价调用
8
+
9
+ macbroom scan # 在终端扫描并打印汇总(不启动服务)
10
+ macbroom scan --json # 输出 JSON,便于脚本 / CI 消费
11
+ macbroom scan --lang en
12
+ macbroom scan --category caches,login_items
13
+
14
+ 仅依赖 Python 3 标准库。
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import argparse
20
+ import json
21
+ import threading
22
+ import webbrowser
23
+
24
+ from macbroom.core import audit
25
+ from macbroom.core.fsutil import human_size
26
+ from macbroom.core.i18n import normalize_lang
27
+ from macbroom.core.server import serve
28
+ from macbroom.scanners import categories as list_categories, scan_category
29
+
30
+ DEFAULT_HOST = "127.0.0.1"
31
+ DEFAULT_PORT = 37700 # 已在端口登记表登记
32
+
33
+
34
+ def _run_serve(args: argparse.Namespace) -> None:
35
+ if not args.no_open:
36
+ url = f"http://{args.host}:{args.port}"
37
+ threading.Timer(1.0, lambda: webbrowser.open(url)).start()
38
+ serve(args.host, args.port)
39
+
40
+
41
+ def _run_scan(args: argparse.Namespace) -> None:
42
+ lang = normalize_lang(args.lang)
43
+ cats = list_categories(lang)
44
+ title_by_key = {c.key: c.title for c in cats}
45
+ icon_by_key = {c.key: c.icon for c in cats}
46
+
47
+ if args.category:
48
+ keys = [k.strip() for k in args.category.split(",") if k.strip()]
49
+ else:
50
+ keys = [c.key for c in cats]
51
+
52
+ results: list[tuple[str, list]] = []
53
+ for key in keys:
54
+ results.append((key, scan_category(key, lang)))
55
+
56
+ all_items = [it for _, items in results for it in items]
57
+ audit.record("cli_scan", categories=keys, count=len(all_items))
58
+
59
+ if args.json:
60
+ print(json.dumps([it.to_dict() for it in all_items],
61
+ ensure_ascii=False, indent=2))
62
+ return
63
+
64
+ grand = 0
65
+ for key, items in results:
66
+ size = sum(it.size or 0 for it in items)
67
+ grand += size
68
+ icon = icon_by_key.get(key, "•")
69
+ title = title_by_key.get(key, key)
70
+ print(f"{icon} {title}: {len(items)} items · {human_size(size)}")
71
+ print("-" * 40)
72
+ print(f"Total reclaimable: {human_size(grand)} across {len(all_items)} items")
73
+ print("Tip: run `macbroom` for the visual UI, or add --json for machine output.")
74
+
75
+
76
+ def _resolve_version() -> str:
77
+ """已安装时以包元数据(pyproject 版本)为准,源码运行回退到 __version__。"""
78
+ try:
79
+ from importlib.metadata import PackageNotFoundError, version
80
+ try:
81
+ return version("macbroom")
82
+ except PackageNotFoundError:
83
+ pass
84
+ except Exception:
85
+ pass
86
+ from macbroom import __version__
87
+ return __version__
88
+
89
+
90
+ def main() -> None:
91
+ parser = argparse.ArgumentParser(description="MacBroom - open-source macOS cleaner")
92
+ parser.add_argument("--version", action="version",
93
+ version=f"macbroom {_resolve_version()}")
94
+ parser.add_argument("--host", default=DEFAULT_HOST)
95
+ parser.add_argument("--port", type=int, default=DEFAULT_PORT)
96
+ parser.add_argument("--no-open", action="store_true", help="不自动打开浏览器")
97
+
98
+ sub = parser.add_subparsers(dest="cmd")
99
+ p_scan = sub.add_parser("scan", help="在终端扫描并输出报告,不启动服务")
100
+ p_scan.add_argument("--json", action="store_true", help="以 JSON 输出,便于脚本消费")
101
+ p_scan.add_argument("--lang", default="zh", help="zh 或 en")
102
+ p_scan.add_argument("--category", default="",
103
+ help="只扫描指定分类,逗号分隔,如 caches,login_items")
104
+
105
+ p_doctor = sub.add_parser("doctor", help="环境预检:Python/macOS/完全磁盘访问/端口等")
106
+ p_doctor.add_argument("--json", action="store_true", help="JSON 输出")
107
+ p_doctor.add_argument("--lang", default="zh", help="zh 或 en")
108
+ p_doctor.add_argument("--port", type=int, default=DEFAULT_PORT,
109
+ help="待检测的 Web UI 端口(默认 37700)")
110
+
111
+ args = parser.parse_args()
112
+ if args.cmd == "scan":
113
+ _run_scan(args)
114
+ elif args.cmd == "doctor":
115
+ from macbroom.doctor import format_report, run_checks
116
+ checks = run_checks(getattr(args, "port", DEFAULT_PORT))
117
+ if args.json:
118
+ print(json.dumps(checks, ensure_ascii=False, indent=2))
119
+ else:
120
+ print(format_report(checks, normalize_lang(args.lang)))
121
+ if not all(c["ok"] for c in checks):
122
+ raise SystemExit(1)
123
+ else:
124
+ _run_serve(args)
125
+
126
+
127
+ if __name__ == "__main__":
128
+ main()
@@ -0,0 +1 @@
1
+ """MacBroom core package."""
@@ -0,0 +1,61 @@
1
+ """操作审计日志:把每次扫描与删除写到本地文件,可事后追溯。
2
+
3
+ 参考 MacSift / MacOS-Maid 的做法:清理工具必须留痕,用户不开调试器也能
4
+ 知道「这个工具到底动了什么」。
5
+
6
+ 设计要点(对应全局「自测数据安全」硬约束):
7
+ - 日志目录可用环境变量 ``MACBROOM_LOG_DIR`` 覆盖,自测一律指向 /tmp,
8
+ 绝不污染用户真实日志目录。
9
+ - 单文件大小封顶,超过就轮转一次(.1),避免无限增长。
10
+ - 仅本地写文件,不发网络,不记录文件内容、仅记录路径与动作。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import json
16
+ import os
17
+ import threading
18
+ import time
19
+
20
+ _DEFAULT_DIR = os.path.join(os.path.expanduser("~"), "Library", "Logs", "MacBroom")
21
+ _MAX_BYTES = 512 * 1024 # 512KB 封顶,超过轮转
22
+ _LOCK = threading.Lock()
23
+
24
+
25
+ def log_dir() -> str:
26
+ return os.environ.get("MACBROOM_LOG_DIR", _DEFAULT_DIR)
27
+
28
+
29
+ def log_path() -> str:
30
+ return os.path.join(log_dir(), "macbroom.log")
31
+
32
+
33
+ def _rotate_if_needed(path: str) -> None:
34
+ try:
35
+ if os.path.getsize(path) <= _MAX_BYTES:
36
+ return
37
+ except OSError:
38
+ return
39
+ backup = path + ".1"
40
+ try:
41
+ if os.path.exists(backup):
42
+ os.remove(backup)
43
+ os.rename(path, backup)
44
+ except OSError:
45
+ pass
46
+
47
+
48
+ def record(event: str, **fields) -> None:
49
+ """追加一条结构化日志。失败时静默(日志不应影响主流程)。"""
50
+ line = {"ts": time.strftime("%Y-%m-%dT%H:%M:%S"), "event": event}
51
+ line.update(fields)
52
+ try:
53
+ with _LOCK:
54
+ d = log_dir()
55
+ os.makedirs(d, exist_ok=True)
56
+ path = log_path()
57
+ _rotate_if_needed(path)
58
+ with open(path, "a", encoding="utf-8") as f:
59
+ f.write(json.dumps(line, ensure_ascii=False) + "\n")
60
+ except OSError:
61
+ pass