Release v1.21.0: Add macos-cleaner skill

- Add macos-cleaner v1.0.0 - Intelligent macOS disk space recovery
- Safety-first philosophy with risk categorization (Safe/Caution/Keep)
- Smart analysis: caches, app remnants, large files, dev environments
- Interactive cleanup with explicit user confirmation
- Bundled scripts: analyze_caches, analyze_dev_env, analyze_large_files,
  find_app_remnants, safe_delete, cleanup_report
- Comprehensive references: cleanup_targets, mole_integration, safety_rules
- Update marketplace to v1.21.0
- Update all documentation (README.md, README.zh-CN.md, CHANGELOG.md, CLAUDE.md)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
daymade
2026-01-11 15:59:13 +08:00
parent 3f2f8f02ca
commit 4d6ed53c1e
16 changed files with 3546 additions and 10 deletions

View File

@@ -5,8 +5,8 @@
"email": "daymadev89@gmail.com"
},
"metadata": {
"description": "Professional Claude Code skills for GitHub operations, document conversion, diagram generation, statusline customization, Teams communication, repomix utilities, skill creation, CLI demo generation, LLM icon access, Cloudflare troubleshooting, UI design system extraction, professional presentation creation, YouTube video downloading, secure repomix packaging, ASR transcription correction, video comparison quality analysis, comprehensive QA testing infrastructure, prompt optimization with EARS methodology, session history recovery, documentation cleanup, PDF generation with Chinese font support, CLAUDE.md progressive disclosure optimization, CCPM skill registry search and management, Promptfoo LLM evaluation framework, iOS app development with XcodeGen and SwiftUI, fact-checking with automated corrections, and Twitter/X content fetching",
"version": "1.20.0",
"description": "Professional Claude Code skills for GitHub operations, document conversion, diagram generation, statusline customization, Teams communication, repomix utilities, skill creation, CLI demo generation, LLM icon access, Cloudflare troubleshooting, UI design system extraction, professional presentation creation, YouTube video downloading, secure repomix packaging, ASR transcription correction, video comparison quality analysis, comprehensive QA testing infrastructure, prompt optimization with EARS methodology, session history recovery, documentation cleanup, PDF generation with Chinese font support, CLAUDE.md progressive disclosure optimization, CCPM skill registry search and management, Promptfoo LLM evaluation framework, iOS app development with XcodeGen and SwiftUI, fact-checking with automated corrections, Twitter/X content fetching, and intelligent macOS disk space recovery",
"version": "1.21.0",
"homepage": "https://github.com/daymade/claude-code-skills"
},
"plugins": [
@@ -279,6 +279,16 @@
"category": "utilities",
"keywords": ["twitter", "x", "social-media", "jina", "content-fetching", "api", "scraping", "threads"],
"skills": ["./twitter-reader"]
},
{
"name": "macos-cleaner",
"description": "Intelligent macOS disk space analysis and cleanup with safety-first philosophy. Use when users report disk space issues, need to clean their Mac, or want to understand storage consumption. Analyzes system caches, application remnants, large files, and development environments (Docker, Homebrew, npm, pip) with risk categorization (Safe/Caution/Keep) and requires explicit user confirmation before any deletions. Includes Mole visual tool integration for hybrid workflow",
"source": "./",
"strict": false,
"version": "1.0.0",
"category": "utilities",
"keywords": ["macos", "disk-space", "cleanup", "cache", "storage", "developer-tools", "docker", "homebrew", "system-maintenance", "safety"],
"skills": ["./macos-cleaner"]
}
]
}

View File

@@ -25,6 +25,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security
- None
## [1.21.0] - 2026-01-11
### Added
- **New Skill**: macos-cleaner - Intelligent macOS disk space analysis and cleanup with safety-first philosophy
- Smart analysis of system caches, application caches, logs, and temporary files
- Application remnant detection (orphaned data from uninstalled apps)
- Large file discovery with automatic categorization (videos, archives, databases, disk images)
- Development environment cleanup (Docker, Homebrew, npm, pip, Git repositories)
- Interactive safe deletion with user confirmation at every step
- Risk-level categorization (🟢 Safe / 🟡 Caution / 🔴 Keep)
- Integration guide for Mole visual cleanup tool
- Before/after cleanup reports with space recovery metrics
- Bundled scripts: `analyze_caches.py`, `analyze_dev_env.py`, `analyze_large_files.py`, `find_app_remnants.py`, `safe_delete.py`, `cleanup_report.py`
- Comprehensive safety rules and cleanup target documentation
- Time Machine backup recommendations for large deletions
- Professional user experience: analyze first, explain thoroughly, execute with confirmation
### Changed
- Updated marketplace skills count from 27 to 28
- Updated marketplace version from 1.20.0 to 1.21.0
- Updated README.md badges (skills count: 28, version: 1.21.0)
- Updated README.md to include macos-cleaner in skills listing
- Updated README.zh-CN.md badges (skills count: 28, version: 1.21.0)
- Updated README.zh-CN.md to include macos-cleaner in skills listing
- Updated CLAUDE.md skills count from 27 to 28
- Added macos-cleaner use case section to README.md
- Added macos-cleaner use case section to README.zh-CN.md
## [1.20.0] - 2026-01-11
### Added

View File

@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Repository Overview
This is a Claude Code skills marketplace containing 27 production-ready skills organized in a plugin marketplace structure. Each skill is a self-contained package that extends Claude's capabilities with specialized knowledge, workflows, and bundled resources.
This is a Claude Code skills marketplace containing 28 production-ready skills organized in a plugin marketplace structure. Each skill is a self-contained package that extends Claude's capabilities with specialized knowledge, workflows, and bundled resources.
**Essential Skill**: `skill-creator` is the most important skill in this marketplace - it's a meta-skill that enables users to create their own skills. Always recommend it first for users interested in extending Claude Code.
@@ -134,7 +134,7 @@ Skills for public distribution must NOT contain:
## Marketplace Configuration
The marketplace is configured in `.claude-plugin/marketplace.json`:
- Contains 27 plugins, each mapping to one skill
- Contains 28 plugins, each mapping to one skill
- Each plugin has: name, description, version, category, keywords, skills array
- Marketplace metadata: name, owner, version, homepage
@@ -187,6 +187,7 @@ The marketplace is configured in `.claude-plugin/marketplace.json`:
25. **iOS-APP-developer** - iOS app development with XcodeGen, SwiftUI, and SPM troubleshooting
26. **fact-checker** - Verify factual claims in documents using web search with automated corrections
27. **twitter-reader** - Fetch Twitter/X post content using Jina.ai API without JavaScript or authentication
28. **macos-cleaner** - Intelligent macOS disk space analysis and cleanup with safety-first philosophy, risk categorization, and interactive confirmation
**Recommendation**: Always suggest `skill-creator` first for users interested in creating skills or extending Claude Code.

111
README.md
View File

@@ -6,15 +6,15 @@
[![简体中文](https://img.shields.io/badge/语言-简体中文-red)](./README.zh-CN.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Skills](https://img.shields.io/badge/skills-27-blue.svg)](https://github.com/daymade/claude-code-skills)
[![Version](https://img.shields.io/badge/version-1.20.0-green.svg)](https://github.com/daymade/claude-code-skills)
[![Skills](https://img.shields.io/badge/skills-28-blue.svg)](https://github.com/daymade/claude-code-skills)
[![Version](https://img.shields.io/badge/version-1.21.0-green.svg)](https://github.com/daymade/claude-code-skills)
[![Claude Code](https://img.shields.io/badge/Claude%20Code-2.0.13+-purple.svg)](https://claude.com/code)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/daymade/claude-code-skills/graphs/commit-activity)
</div>
Professional Claude Code skills marketplace featuring 27 production-ready skills for enhanced development workflows.
Professional Claude Code skills marketplace featuring 28 production-ready skills for enhanced development workflows.
## 📑 Table of Contents
@@ -1047,6 +1047,106 @@ python scripts/fetch_tweet.py https://x.com/user/status/123 output.md
---
### 26. **macos-cleaner** - Intelligent macOS Disk Space Recovery
**The safest way to reclaim disk space on macOS.** Analyze system caches, application remnants, large files, and development environments with intelligent categorization and interactive cleanup.
**Why macos-cleaner stands out:**
- **Safety-First Philosophy**: Never deletes without explicit user confirmation. Every operation includes risk assessment (🟢 Safe / 🟡 Caution / 🔴 Keep).
- **Intelligence Over Automation**: Analyzes first, explains thoroughly, then lets you decide. Unlike one-click cleaners that blindly delete, we help you understand what you're removing and why.
- **Developer-Friendly**: Deep analysis of Docker, Homebrew, npm, pip caches - tools that generic cleaners miss.
- **Transparent & Educational**: Every recommendation includes an explanation of what the file is, why it's safe (or not), and what happens if you delete it.
- **Professional Quality**: Built by developers who know the pain of accidentally deleting important files. Includes comprehensive safety checks and Time Machine backup recommendations.
**Our design principles:**
1. **User Control First**: You make the decisions, we provide the insights
2. **Explain Everything**: No mysterious deletions - full transparency on impact
3. **Conservative Defaults**: When uncertain, we preserve rather than delete
4. **Developer Context**: Understand development tool caches, not just system files
5. **Hybrid Approach**: Combine script precision with visual tools (Mole integration)
**When to use:**
- Your Mac is running out of disk space (>80% full)
- You're a developer with Docker/npm/pip/Homebrew caches piling up
- You want to understand what's consuming space, not just delete blindly
- You need to clean up after uninstalled applications
- You prefer understanding over automation
**Key features:**
- **Smart Cache Analysis**: Categorizes system caches, app caches, logs by safety level
- **Application Remnant Detection**: Finds orphaned data from uninstalled apps with confidence scoring
- **Large File Discovery**: Intelligent categorization (videos, archives, databases, disk images, build artifacts)
- **Development Environment Cleanup**: Docker (images, containers, volumes, build cache), Homebrew, npm, pip, old Git repos
- **Interactive Safe Deletion**: Batch confirmation, selective deletion, undo-friendly (uses Trash when possible)
- **Before/After Reports**: Track space recovery with detailed breakdown
- **Mole Integration**: Seamless workflow with visual cleanup tool for GUI preferences
- **Risk Categorization**: Every item labeled with safety level and explanation
- **Time Machine Awareness**: Recommends backups before large deletions (>10 GB)
**What makes us different:**
-**Trust Through Transparency**: Other cleaners hide what they delete. We show everything and explain why.
-**Developer-Centric**: We clean Docker, not just browser caches. We understand `.git` directories, `node_modules`, and build artifacts.
-**Safety Checks Built-In**: Protection against deleting system files, user data, credentials, active databases, or files in use.
-**Educational**: Learn what's safe to delete and why, so you can maintain your Mac confidently.
-**Not a One-Click Solution**: We don't delete automatically. If you want "clean everything now", use other tools. We're for users who want control.
**Example usage:**
```bash
# Install the skill
claude plugin install macos-cleaner@daymade-skills
# Ask Claude Code to analyze your Mac
"My Mac is running out of space, help me analyze what's using storage"
# Claude will:
# 1. Run comprehensive disk analysis
# 2. Present categorized findings with safety levels
# 3. Explain each category (caches, remnants, large files, dev tools)
# 4. Recommend cleanup approach
# 5. Execute ONLY what you confirm
# Example analysis output:
📊 Disk Space Analysis
━━━━━━━━━━━━━━━━━━━━━━━━
Total: 500 GB
Used: 450 GB (90%)
Available: 50 GB (10%)
🟢 Safe to Clean (95 GB):
- System caches: 45 GB (apps regenerate automatically)
- Homebrew cache: 5 GB (reinstalls when needed)
- npm cache: 3 GB (safe to clear)
- Old logs: 8 GB (diagnostic data only)
- Trash: 34 GB (already marked for deletion)
🟡 Review Recommended (62 GB):
- Large downloads: 38 GB (may contain important files)
- App remnants: 8 GB (verify apps are truly uninstalled)
- Docker images: 12 GB (may be in use)
- Old .git repos: 4 GB (verify project is archived)
🔴 Keep Unless Certain (0 GB):
- No high-risk items detected
Recommendation: Start with 🟢 Safe items (95 GB), then review 🟡 items together.
```
**🎬 Live Demo**
*Coming soon*
📚 **Documentation**: See [macos-cleaner/references/](./macos-cleaner/references/) for:
- `cleanup_targets.md` - Detailed explanations of every cleanup target
- `mole_integration.md` - How to combine scripts with Mole visual tool
- `safety_rules.md` - Comprehensive safety guidelines and what to never delete
**Requirements**:
- **Python 3.6+** (pre-installed on macOS)
- **macOS** (tested on macOS 10.15+)
- **Optional**: [Mole](https://github.com/tw93/Mole) for visual cleanup interface
---
## 🎬 Interactive Demo Gallery
Want to see all demos in one place with click-to-enlarge functionality? Check out our [interactive demo gallery](./demos/index.html) or browse the [demos directory](./demos/).
@@ -1107,6 +1207,9 @@ Use **promptfoo-evaluation** to set up prompt tests, compare model outputs, and
### For iOS App Development
Use **iOS-APP-developer** to configure XcodeGen projects, resolve SPM dependency issues, and troubleshoot code signing or device deployment.
### For macOS System Maintenance & Disk Space Recovery
Use **macos-cleaner** to intelligently analyze and reclaim disk space on macOS with safety-first approach. Unlike one-click cleaners that blindly delete, macos-cleaner explains what each file is, categorizes by risk level (🟢/🟡/🔴), and requires explicit confirmation before any deletion. Perfect for developers dealing with Docker/Homebrew/npm/pip cache bloat, users wanting to understand storage consumption, or anyone who values transparency over automation. Combines script-based precision with optional Mole visual tool integration for hybrid workflow.
### For Twitter/X Content Research
Use **twitter-reader** to fetch tweet content without JavaScript rendering or authentication. Perfect for documenting social media discussions, archiving threads, analyzing tweet content, or gathering reference material from Twitter/X. Combine with **markdown-tools** to convert fetched content into other formats, or with **repomix-safe-mixer** to package research collections securely.
@@ -1146,6 +1249,7 @@ Each skill includes:
- **promptfoo-evaluation**: See `promptfoo-evaluation/references/promptfoo_api.md` for evaluation patterns
- **iOS-APP-developer**: See `iOS-APP-developer/references/xcodegen-full.md` for XcodeGen options and project.yml details
- **twitter-reader**: See `twitter-reader/SKILL.md` for API key setup and URL format support
- **macos-cleaner**: See `macos-cleaner/references/cleanup_targets.md` for detailed cleanup target explanations, `macos-cleaner/references/mole_integration.md` for Mole visual tool integration, and `macos-cleaner/references/safety_rules.md` for comprehensive safety guidelines
## 🛠️ Requirements
@@ -1163,6 +1267,7 @@ Each skill includes:
- **ccusage** (optional, for statusline cost tracking)
- **pandas & matplotlib** (optional, for ppt-creator chart generation)
- **Marp CLI** (optional, for ppt-creator Marp PPTX export): `npm install -g @marp-team/marp-cli`
- **Mole** (optional, for macos-cleaner visual cleanup): Download from https://github.com/tw93/Mole
- **repomix** (for repomix-safe-mixer): `npm install -g repomix`
- **CCPM CLI** (for skills-search): `npm install -g @daymade/ccpm`
- **Promptfoo** (for promptfoo-evaluation): `npx promptfoo@latest`

View File

@@ -6,15 +6,15 @@
[![简体中文](https://img.shields.io/badge/语言-简体中文-red)](./README.zh-CN.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Skills](https://img.shields.io/badge/skills-27-blue.svg)](https://github.com/daymade/claude-code-skills)
[![Version](https://img.shields.io/badge/version-1.20.0-green.svg)](https://github.com/daymade/claude-code-skills)
[![Skills](https://img.shields.io/badge/skills-28-blue.svg)](https://github.com/daymade/claude-code-skills)
[![Version](https://img.shields.io/badge/version-1.21.0-green.svg)](https://github.com/daymade/claude-code-skills)
[![Claude Code](https://img.shields.io/badge/Claude%20Code-2.0.13+-purple.svg)](https://claude.com/code)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/daymade/claude-code-skills/graphs/commit-activity)
</div>
专业的 Claude Code 技能市场,提供 27 个生产就绪的技能,用于增强开发工作流。
专业的 Claude Code 技能市场,提供 28 个生产就绪的技能,用于增强开发工作流。
## 📑 目录
@@ -216,6 +216,9 @@ claude plugin install iOS-APP-developer@daymade-skills
# Twitter/X 内容获取
claude plugin install twitter-reader@daymade-skills
# macOS 磁盘空间清理
claude plugin install macos-cleaner@daymade-skills
```
每个技能都可以独立安装 - 只选择你需要的!
@@ -1086,6 +1089,106 @@ python scripts/fetch_tweet.py https://x.com/user/status/123 output.md
---
### 26. **macos-cleaner** - 智能 macOS 磁盘空间恢复
**在 macOS 上恢复磁盘空间最安全的方式。** 通过智能分类和交互式清理,分析系统缓存、应用残留、大文件和开发环境。
**为什么 macos-cleaner 与众不同:**
- **安全优先理念**:在明确用户确认之前绝不删除。每项操作都包含风险评估(🟢 安全 / 🟡 谨慎 / 🔴 保留)。
- **智能胜于自动化**:先分析,详细解释,然后由你决定。与盲目删除的一键清理工具不同,我们帮助你理解要删除的内容及原因。
- **开发者友好**:深度分析 Docker、Homebrew、npm、pip 缓存 - 这些是通用清理工具遗漏的工具。
- **透明且教育性**:每项建议都包含对文件的解释、为什么安全(或不安全)以及删除后的影响。
- **专业品质**:由了解误删重要文件痛苦的开发者构建。包含全面的安全检查和 Time Machine 备份建议。
**我们的设计原则:**
1. **用户控制优先**:你做决定,我们提供洞察
2. **解释一切**:没有神秘的删除 - 完全透明的影响说明
3. **保守的默认值**:不确定时,我们保留而不是删除
4. **开发者视角**:理解开发工具缓存,而不仅仅是系统文件
5. **混合方法**结合脚本精度与可视化工具Mole 集成)
**使用场景:**
- 你的 Mac 磁盘空间不足(使用率 >80%
- 你是开发者Docker/npm/pip/Homebrew 缓存堆积如山
- 你想了解占用空间的内容,而不仅仅是盲目删除
- 你需要清理已卸载应用程序的残留
- 你更喜欢理解而非自动化
**主要功能:**
- **智能缓存分析**:按安全级别对系统缓存、应用缓存、日志进行分类
- **应用残留检测**:查找已卸载应用程序的孤立数据,并提供可信度评分
- **大文件发现**:智能分类(视频、归档、数据库、磁盘镜像、构建产物)
- **开发环境清理**Docker镜像、容器、卷、构建缓存、Homebrew、npm、pip、旧 Git 仓库
- **交互式安全删除**:批量确认、选择性删除、撤销友好(尽可能使用废纸篓)
- **前后报告**:跟踪空间恢复并提供详细分解
- **Mole 集成**:与可视化清理工具无缝协作,适合 GUI 偏好
- **风险分类**:每个项目都标有安全级别和说明
- **Time Machine 感知**:建议在大批量删除(>10 GB前进行备份
**我们的优势:**
-**通过透明度建立信任**:其他清理工具隐藏删除内容。我们展示一切并解释原因。
-**以开发者为中心**:我们清理 Docker而不仅仅是浏览器缓存。我们理解 `.git` 目录、`node_modules` 和构建产物。
-**内置安全检查**:保护系统文件、用户数据、凭据、活动数据库或正在使用的文件不被删除。
-**教育性**:了解什么可以安全删除及原因,以便你能自信地维护你的 Mac。
-**不是一键解决方案**:我们不会自动删除。如果你想要"立即清理所有内容",请使用其他工具。我们面向想要控制的用户。
**示例用法:**
```bash
# 安装技能
claude plugin install macos-cleaner@daymade-skills
# 要求 Claude Code 分析你的 Mac
"我的 Mac 快没空间了,帮我分析一下是什么在占用存储空间"
# Claude 将会:
# 1. 运行全面的磁盘分析
# 2. 展示带有安全级别的分类结果
# 3. 解释每个类别(缓存、残留、大文件、开发工具)
# 4. 推荐清理方法
# 5. 仅执行你确认的操作
# 示例分析输出:
📊 磁盘空间分析
━━━━━━━━━━━━━━━━━━━━━━━
总计: 500 GB
已用: 450 GB (90%)
可用: 50 GB (10%)
🟢 安全清理 (95 GB):
- 系统缓存: 45 GB (应用会自动重新生成)
- Homebrew 缓存: 5 GB (需要时重新安装)
- npm 缓存: 3 GB (清除安全)
- 旧日志: 8 GB (仅诊断数据)
- 废纸篓: 34 GB (已标记为删除)
🟡 建议审查 (62 GB):
- 大型下载: 38 GB (可能包含重要文件)
- 应用残留: 8 GB (验证应用是否真正卸载)
- Docker 镜像: 12 GB (可能正在使用)
- 旧 .git 仓库: 4 GB (验证项目是否已归档)
🔴 除非确定否则保留 (0 GB):
- 未检测到高风险项目
建议:从 🟢 安全项目开始 (95 GB),然后一起审查 🟡 项目。
```
**🎬 实时演示**
*即将推出*
📚 **文档**:参见 [macos-cleaner/references/](./macos-cleaner/references/) 了解:
- `cleanup_targets.md` - 每个清理目标的详细说明
- `mole_integration.md` - 如何将脚本与 Mole 可视化工具结合使用
- `safety_rules.md` - 全面的安全指南以及永远不应删除的内容
**要求**
- **Python 3.6+**macOS 预装)
- **macOS**(在 macOS 10.15+ 上测试)
- **可选**[Mole](https://github.com/tw93/Mole) 用于可视化清理界面
---
## 🎬 交互式演示画廊
想要在一个地方查看所有演示并具有点击放大功能?访问我们的[交互式演示画廊](./demos/index.html)或浏览[演示目录](./demos/)。
@@ -1146,6 +1249,9 @@ python scripts/fetch_tweet.py https://x.com/user/status/123 output.md
### Twitter/X 内容研究
使用 **twitter-reader** 无需 JavaScript 渲染或身份验证即可获取推文内容。非常适合记录社交媒体讨论、归档话题、分析推文内容或从 Twitter/X 收集参考资料。与 **markdown-tools** 结合可将获取的内容转换为其他格式,或与 **repomix-safe-mixer** 结合安全地打包研究集合。
### macOS 系统维护与磁盘空间恢复
使用 **macos-cleaner** 以安全优先的方式智能分析和恢复 macOS 上的磁盘空间。与盲目删除的一键清理工具不同macos-cleaner 解释每个文件是什么、按风险级别分类(🟢/🟡/🔴),并在任何删除前需要明确确认。非常适合处理 Docker/Homebrew/npm/pip 缓存膨胀的开发者、希望了解存储空间消耗的用户,或任何重视透明度而非自动化的人。结合基于脚本的精度和可选的 Mole 可视化工具集成以实现混合工作流。
### 技能发现与管理
使用 **skills-search** 从 CCPM 注册表中查找、安装和管理 Claude Code 技能。非常适合为特定任务发现新技能、为常见工作流安装技能包,以及保持技能集合的有序管理。
@@ -1185,6 +1291,7 @@ python scripts/fetch_tweet.py https://x.com/user/status/123 output.md
- **promptfoo-evaluation**:参见 `promptfoo-evaluation/references/promptfoo_api.md` 了解评测模式
- **iOS-APP-developer**:参见 `iOS-APP-developer/references/xcodegen-full.md` 了解 XcodeGen 选项与 project.yml 细节
- **twitter-reader**:参见 `twitter-reader/SKILL.md` 了解 API 密钥设置和 URL 格式支持
- **macos-cleaner**:参见 `macos-cleaner/references/cleanup_targets.md` 了解详细清理目标说明、`macos-cleaner/references/mole_integration.md` 了解 Mole 可视化工具集成、`macos-cleaner/references/safety_rules.md` 了解全面安全指南
## 🛠️ 系统要求
@@ -1203,6 +1310,7 @@ python scripts/fetch_tweet.py https://x.com/user/status/123 output.md
- **Promptfoo**(用于 promptfoo-evaluation`npx promptfoo@latest`
- **macOS + Xcode、XcodeGen**(用于 iOS-APP-developer
- **Jina.ai API 密钥**(用于 twitter-readerhttps://jina.ai/ 提供免费套餐
- **Mole**(可选,用于 macos-cleaner 可视化清理):从 https://github.com/tw93/Mole 下载
## ❓ 常见问题

View File

@@ -0,0 +1,4 @@
Security scan passed
Scanned at: 2026-01-11T15:33:50.497864
Tool: gitleaks + pattern-based validation
Content hash: 837b8b7dfa3a728295649b608acaba00d7eb2b1fbbe02a35f5c8e0ffc8c2e361

528
macos-cleaner/SKILL.md Normal file
View File

@@ -0,0 +1,528 @@
---
name: macos-cleaner
description: Analyze and reclaim macOS disk space through intelligent cleanup recommendations. This skill should be used when users report disk space issues, need to clean up their Mac, or want to understand what's consuming storage. Focus on safe, interactive analysis with user confirmation before any deletions.
---
# macOS Cleaner
## Overview
Intelligently analyze macOS disk usage and provide actionable cleanup recommendations to reclaim storage space. This skill follows a **safety-first philosophy**: analyze thoroughly, present clear findings, and require explicit user confirmation before executing any deletions.
**Target users**: Users with basic technical knowledge who understand file systems but need guidance on what's safe to delete on macOS.
## Core Principles
1. **Analyze First, Act Second**: Never delete files without explicit user confirmation
2. **Transparency**: Explain what each file/directory is and why it's safe (or unsafe) to delete
3. **Interactive Decision Making**: Present findings in human-readable format, let users decide
4. **Conservative Defaults**: When in doubt, don't delete
5. **Backup Suggestions**: Recommend Time Machine backup before major cleanups
## Workflow Decision Tree
```
User reports disk space issues
Quick Diagnosis
┌──────┴──────┐
│ │
Immediate Deep Analysis
Cleanup (continue below)
│ │
└──────┬──────┘
Present Findings
User Confirms
Execute Cleanup
Verify Results
```
## Step 1: Quick Diagnosis
Start with a rapid assessment to understand the scope:
```bash
# Check available disk space
df -h /
# Find top 10 largest directories in home folder
du -h -d 1 ~ | sort -hr | head -n 10
# Quick check for common space hogs
du -sh ~/Library/Caches ~/Library/Logs ~/Downloads ~/.Trash 2>/dev/null
```
**Present findings in this format:**
```
📊 Disk Space Analysis
━━━━━━━━━━━━━━━━━━━━━━━━
Total: 500 GB
Used: 450 GB (90%)
Available: 50 GB (10%)
🔍 Top Space Consumers:
1. ~/Library/Caches 45 GB
2. ~/Downloads 38 GB
3. ~/Library/Application Support 25 GB
4. ~/.Trash 12 GB
5. ~/Library/Logs 8 GB
⚡ Quick Win Opportunities:
- Empty Trash: ~12 GB
- Clear Downloads: ~38 GB (requires user review)
- System Caches: ~45 GB (mostly safe to clear)
```
## Step 2: Deep Analysis Categories
Scan the following categories systematically. Reference `references/cleanup_targets.md` for detailed explanations.
### Category 1: System & Application Caches
**Locations to analyze:**
- `~/Library/Caches/*` - User application caches
- `/Library/Caches/*` - System-wide caches (requires sudo)
- `~/Library/Logs/*` - Application logs
- `/var/log/*` - System logs (requires sudo)
**Analysis script:**
```bash
scripts/analyze_caches.py --user-only
```
**Safety level**: 🟢 Generally safe to delete (apps regenerate caches)
**Exceptions to preserve:**
- Browser caches while browser is running
- IDE caches (may slow down next startup)
- Package manager caches (Homebrew, pip, npm)
### Category 2: Application Remnants
**Locations to analyze:**
- `~/Library/Application Support/*` - App data
- `~/Library/Preferences/*` - Preference files
- `~/Library/Containers/*` - Sandboxed app data
**Analysis approach:**
1. List installed applications in `/Applications`
2. Cross-reference with `~/Library/Application Support`
3. Identify orphaned folders (app uninstalled but data remains)
**Analysis script:**
```bash
scripts/find_app_remnants.py
```
**Safety level**: 🟡 Caution required
- ✅ Safe: Folders for clearly uninstalled apps
- ⚠️ Check first: Folders for apps you rarely use
- ❌ Keep: Active application data
### Category 3: Large Files & Duplicates
**Analysis script:**
```bash
scripts/analyze_large_files.py --threshold 100MB --path ~
```
**Find duplicates (optional, resource-intensive):**
```bash
# Use fdupes if installed
if command -v fdupes &> /dev/null; then
fdupes -r ~/Documents ~/Downloads
fi
```
**Present findings:**
```
📦 Large Files (>100MB):
━━━━━━━━━━━━━━━━━━━━━━━━
1. movie.mp4 4.2 GB ~/Downloads
2. dataset.csv 1.8 GB ~/Documents/data
3. old_backup.zip 1.5 GB ~/Desktop
...
🔁 Duplicate Files:
- screenshot.png (3 copies) 15 MB each
- document_v1.docx (2 copies) 8 MB each
```
**Safety level**: 🟡 User judgment required
### Category 4: Development Environment Cleanup
**Targets:**
- Docker: images, containers, volumes, build cache
- Homebrew: cache, old versions
- Node.js: `node_modules`, npm cache
- Python: pip cache, `__pycache__`, venv
- Git: `.git` folders in archived projects
**Analysis script:**
```bash
scripts/analyze_dev_env.py
```
**Example findings:**
```
🐳 Docker Resources:
- Unused images: 12 GB
- Stopped containers: 2 GB
- Build cache: 8 GB
- Orphaned volumes: 3 GB
Total potential: 25 GB
📦 Package Managers:
- Homebrew cache: 5 GB
- npm cache: 3 GB
- pip cache: 1 GB
Total potential: 9 GB
🗂️ Old Projects:
- archived-project-2022/.git 500 MB
- old-prototype/.git 300 MB
```
**Cleanup commands (require confirmation):**
```bash
# Docker cleanup
docker system prune -a --volumes
# Homebrew cleanup
brew cleanup -s
# npm cache
npm cache clean --force
# pip cache
pip cache purge
```
**Safety level**: 🟢 Safe for development caches, 🟡 Caution for Docker volumes
## Step 3: Integration with Mole
**Mole** (https://github.com/tw93/Mole) is a visual macOS cleaner. Recommend it as a complementary tool for users who want GUI-based cleanup.
**When to suggest Mole:**
- User prefers visual interface over command-line
- User wants one-click cleaning for common targets
- Script analysis reveals complex cleanup needs
**How to integrate:**
1. **Check if Mole is installed:**
```bash
if [ -d "/Applications/Mole.app" ]; then
echo "✅ Mole is installed"
else
echo "💡 Consider installing Mole for visual cleanup: https://github.com/tw93/Mole"
fi
```
2. **Coordinate workflow:**
- Use scripts for detailed analysis and reports
- Suggest Mole for executing approved cleanups
- Use scripts for developer-specific cleanup (Docker, npm, etc.)
3. **Reference guide:**
See `references/mole_integration.md` for detailed usage.
## Step 4: Present Recommendations
Format findings into actionable recommendations with risk levels:
```markdown
# macOS Cleanup Recommendations
## Summary
Total space recoverable: ~XX GB
Current usage: XX%
## Recommended Actions
### 🟢 Safe to Execute (Low Risk)
These are safe to delete and will be regenerated as needed:
1. **Empty Trash** (~12 GB)
- Location: ~/.Trash
- Command: `rm -rf ~/.Trash/*`
2. **Clear System Caches** (~45 GB)
- Location: ~/Library/Caches
- Command: `rm -rf ~/Library/Caches/*`
- Note: Apps may be slightly slower on next launch
3. **Remove Homebrew Cache** (~5 GB)
- Command: `brew cleanup -s`
### 🟡 Review Recommended (Medium Risk)
Review these items before deletion:
1. **Large Downloads** (~38 GB)
- Location: ~/Downloads
- Action: Manually review and delete unneeded files
- Files: [list top 10 largest files]
2. **Application Remnants** (~8 GB)
- Apps: [list detected uninstalled apps]
- Locations: [list paths]
- Action: Confirm apps are truly uninstalled before deleting data
### 🔴 Keep Unless Certain (High Risk)
Only delete if you know what you're doing:
1. **Docker Volumes** (~3 GB)
- May contain important data
- Review with: `docker volume ls`
2. **Time Machine Local Snapshots** (~XX GB)
- Automatic backups, will be deleted when space needed
- Command to check: `tmutil listlocalsnapshots /`
```
## Step 5: Execute with Confirmation
**CRITICAL**: Never execute deletions without explicit user confirmation.
**Interactive confirmation flow:**
```python
# Example from scripts/safe_delete.py
def confirm_delete(path: str, size: str, description: str) -> bool:
"""
Ask user to confirm deletion.
Args:
path: File/directory path
size: Human-readable size
description: What this file/directory is
Returns:
True if user confirms, False otherwise
"""
print(f"\n🗑 Confirm Deletion")
print(f"━━━━━━━━━━━━━━━━━━")
print(f"Path: {path}")
print(f"Size: {size}")
print(f"Description: {description}")
response = input("\nDelete this item? [y/N]: ").strip().lower()
return response == 'y'
```
**For batch operations:**
```python
def batch_confirm(items: list) -> list:
"""
Show all items, ask for batch confirmation.
Returns list of items user approved.
"""
print("\n📋 Items to Delete:")
print("━━━━━━━━━━━━━━━━━━")
for i, item in enumerate(items, 1):
print(f"{i}. {item['path']} ({item['size']})")
print("\nOptions:")
print(" 'all' - Delete all items")
print(" '1,3,5' - Delete specific items by number")
print(" 'none' - Cancel")
response = input("\nYour choice: ").strip().lower()
if response == 'none':
return []
elif response == 'all':
return items
else:
# Parse numbers
indices = [int(x.strip()) - 1 for x in response.split(',')]
return [items[i] for i in indices if 0 <= i < len(items)]
```
## Step 6: Verify Results
After cleanup, verify the results and report back:
```bash
# Compare before/after
df -h /
# Calculate space recovered
# (handled by scripts/cleanup_report.py)
```
**Report format:**
```
✅ Cleanup Complete!
Before: 450 GB used (90%)
After: 385 GB used (77%)
━━━━━━━━━━━━━━━━━━━━━━━━
Recovered: 65 GB
Breakdown:
- System caches: 45 GB
- Downloads: 12 GB
- Homebrew cache: 5 GB
- Application remnants: 3 GB
⚠️ Notes:
- Some applications may take longer to launch on first run
- Deleted items cannot be recovered unless you have Time Machine backup
- Consider running this cleanup monthly
💡 Maintenance Tips:
- Set up automatic Homebrew cleanup: `brew cleanup` weekly
- Review Downloads folder monthly
- Enable "Empty Trash Automatically" in Finder preferences
```
## Safety Guidelines
### Always Preserve
Never delete these without explicit user instruction:
- `~/Documents`, `~/Desktop`, `~/Pictures` content
- Active project directories
- Database files (*.db, *.sqlite)
- Configuration files for active apps
- SSH keys, credentials, certificates
- Time Machine backups
### Require Sudo Confirmation
These operations require elevated privileges. Ask user to run commands manually:
- Clearing `/Library/Caches` (system-wide)
- Clearing `/var/log` (system logs)
- Clearing `/private/var/folders` (system temp)
Example prompt:
```
⚠️ This operation requires administrator privileges.
Please run this command manually:
sudo rm -rf /Library/Caches/*
⚠️ You'll be asked for your password.
```
### Backup Recommendation
Before executing any cleanup >10GB, recommend:
```
💡 Safety Tip:
Before cleaning XX GB, consider creating a Time Machine backup.
Quick backup check:
tmutil latestbackup
If no recent backup, run:
tmutil startbackup
```
## Troubleshooting
### "Operation not permitted" errors
macOS may block deletion of certain system files due to SIP (System Integrity Protection).
**Solution**: Don't force it. These protections exist for security.
### App crashes after cache deletion
Rare but possible. **Solution**: Restart the app, it will regenerate necessary caches.
### Docker cleanup removes important data
**Prevention**: Always list Docker volumes before cleanup:
```bash
docker volume ls
docker volume inspect <volume_name>
```
## Resources
### scripts/
- `analyze_caches.py` - Scan and categorize cache directories
- `find_app_remnants.py` - Detect orphaned application data
- `analyze_large_files.py` - Find large files with smart filtering
- `analyze_dev_env.py` - Scan development environment resources
- `safe_delete.py` - Interactive deletion with confirmation
- `cleanup_report.py` - Generate before/after reports
### references/
- `cleanup_targets.md` - Detailed explanations of each cleanup target
- `mole_integration.md` - How to use Mole alongside this skill
- `safety_rules.md` - Comprehensive list of what to never delete
## Usage Examples
### Example 1: Quick Cache Cleanup
User request: "My Mac is running out of space, can you help?"
Workflow:
1. Run quick diagnosis
2. Identify system caches as quick win
3. Present findings: "45 GB in ~/Library/Caches"
4. Explain: "These are safe to delete, apps will regenerate them"
5. Ask confirmation
6. Execute: `rm -rf ~/Library/Caches/*`
7. Report: "Recovered 45 GB"
### Example 2: Development Environment Cleanup
User request: "I'm a developer and my disk is full"
Workflow:
1. Run `scripts/analyze_dev_env.py`
2. Present Docker + npm + Homebrew findings
3. Explain each category
4. Provide cleanup commands with explanations
5. Let user execute (don't auto-execute Docker cleanup)
6. Verify results
### Example 3: Finding Large Files
User request: "What's taking up so much space?"
Workflow:
1. Run `scripts/analyze_large_files.py --threshold 100MB`
2. Present top 20 large files with context
3. Categorize: videos, datasets, archives, disk images
4. Let user decide what to delete
5. Execute confirmed deletions
6. Suggest archiving to external drive
## Best Practices
1. **Start Conservative**: Begin with obviously safe targets (caches, trash)
2. **Explain Everything**: Users should understand what they're deleting
3. **Show Examples**: List 3-5 example files from each category
4. **Respect User Pace**: Don't rush through confirmations
5. **Document Results**: Always show before/after space usage
6. **Educate**: Include maintenance tips in final report
7. **Integrate Tools**: Suggest Mole for users who prefer GUI
## When NOT to Use This Skill
- User wants automatic/silent cleanup (against safety-first principle)
- User needs Windows/Linux cleanup (macOS-specific skill)
- User has <10% disk usage (no cleanup needed)
- User wants to clean system files requiring SIP disable (security risk)
In these cases, explain limitations and suggest alternatives.

View File

@@ -0,0 +1,430 @@
# macOS Cleanup Targets Reference
Detailed explanations of cleanup targets, their safety levels, and impact.
## System Caches
### ~/Library/Caches
**What it is**: Application-level cache storage for user applications.
**Contents**:
- Browser caches (Chrome, Firefox, Safari)
- Application temporary files
- Download caches
- Thumbnail caches
- Font caches
**Safety**: 🟢 **Safe to delete**
**Impact**:
- Apps may be slower on first launch after deletion
- Websites may load slower on first visit (need to re-download assets)
- No data loss (caches are regenerated)
**Size**: Typically 10-100 GB depending on usage
**Cleanup command**:
```bash
rm -rf ~/Library/Caches/*
```
### /Library/Caches
**What it is**: System-level cache storage (shared across all users).
**Safety**: 🟢 **Safe to delete** (requires sudo)
**Impact**: Same as user caches, but system-wide
**Cleanup command**:
```bash
sudo rm -rf /Library/Caches/*
```
### Package Manager Caches
#### Homebrew Cache
**Location**: `$(brew --cache)` (typically `~/Library/Caches/Homebrew`)
**What it is**: Downloaded package installers and build artifacts
**Safety**: 🟢 **Safe to delete**
**Impact**: Will need to re-download packages on next install/upgrade
**Cleanup**:
```bash
brew cleanup -s # Safe cleanup (removes old versions)
brew cleanup --prune=all # Aggressive cleanup (removes all cached downloads)
```
#### npm Cache
**Location**: `~/.npm` or configured cache directory
**Safety**: 🟢 **Safe to delete**
**Impact**: Packages will be re-downloaded when needed
**Cleanup**:
```bash
npm cache clean --force
```
#### pip Cache
**Location**: `~/Library/Caches/pip` (macOS)
**Safety**: 🟢 **Safe to delete**
**Impact**: Packages will be re-downloaded when needed
**Cleanup**:
```bash
pip cache purge
# or for pip3
pip3 cache purge
```
## Application Logs
### ~/Library/Logs
**What it is**: Application log files
**Safety**: 🟢 **Safe to delete**
**Impact**: Loss of diagnostic information (only matters if debugging)
**Typical size**: 1-20 GB
**Cleanup**:
```bash
rm -rf ~/Library/Logs/*
```
### /var/log (System Logs)
**What it is**: System and service log files
**Safety**: 🟢 **Safe to delete old logs** (requires sudo)
**Impact**: Loss of system diagnostic history
**Note**: macOS automatically rotates logs, manual deletion rarely needed
## Application Data
### ~/Library/Application Support
**What it is**: Persistent application data, settings, and databases
**Safety**: 🟡 **Caution required**
**Contains**:
- Application databases
- User preferences and settings
- Downloaded content
- Plugins and extensions
- Save games
**When safe to delete**:
- Application is confirmed uninstalled
- Folder belongs to trial software no longer used
- Folder is for outdated version of app (check first!)
**When to KEEP**:
- Active applications
- Any folder you're uncertain about
**Recommendation**: Use `find_app_remnants.py` to identify orphaned data
### ~/Library/Containers
**What it is**: Sandboxed application data (for App Store apps)
**Safety**: 🟡 **Caution required**
**Same rules** as Application Support - only delete for uninstalled apps
### ~/Library/Preferences
**What it is**: Application preference files (.plist)
**Safety**: 🟡 **Caution required**
**Impact of deletion**: App returns to default settings
**When to delete**:
- App is confirmed uninstalled
- Troubleshooting a misbehaving app (as last resort)
## Development Environment
### Docker
#### Images
**What it is**: Container images (base OS + application layers)
**Safety**: 🟢 **Safe to delete unused images**
**Check first**:
```bash
docker images
```
**Cleanup**:
```bash
docker image prune -a # Remove all unused images
```
#### Containers
**What it is**: Running or stopped container instances
**Safety**: 🟢 **Safe to delete stopped containers**
**Check first**:
```bash
docker ps -a
```
**Cleanup**:
```bash
docker container prune # Remove stopped containers
```
#### Volumes
**What it is**: Persistent data storage for containers
**Safety**: 🔴 **CAUTION - May contain important data**
**Check first**:
```bash
docker volume ls
docker volume inspect <volume_name>
```
**Cleanup** (only if certain):
```bash
docker volume prune # Remove unused volumes
```
#### Build Cache
**What it is**: Intermediate build layers
**Safety**: 🟢 **Safe to delete**
**Cleanup**:
```bash
docker builder prune -a
```
#### All-in-one cleanup
⚠️ **WARNING**: This removes ALL unused Docker resources including volumes!
```bash
docker system prune -a --volumes
```
### node_modules
**What it is**: Installed npm packages for Node.js projects
**Safety**: 🟢 **Safe to delete** (can be regenerated)
**Impact**: Need to run `npm install` to restore
**Finding large node_modules**:
```bash
find ~ -name "node_modules" -type d -prune -print 2>/dev/null | while read dir; do
du -sh "$dir"
done | sort -hr
```
**Cleanup**:
```bash
# For old projects
rm -rf /path/to/old-project/node_modules
```
### Python Virtual Environments
**What it is**: Isolated Python environments
**Location**: `venv/`, `.venv/`, `env/` in project directories
**Safety**: 🟢 **Safe to delete** (can be recreated)
**Impact**: Need to recreate virtualenv and reinstall packages
**Finding venvs**:
```bash
find ~ -type d -name "venv" -o -name ".venv" 2>/dev/null
```
### Git Repositories (.git directories)
**What it is**: Git version control data
**Safety**: 🟡 **Depends on use case**
**When SAFE to delete**:
- Project is archived and you have remote backup
- You only need final code, not history
**When to KEEP**:
- Active development
- No remote backup exists
- You might need the history
**Cleanup** (convert to plain folder, lose history):
```bash
rm -rf /path/to/old-project/.git
```
## Large Files
### Downloads Folder
**What it is**: Files downloaded from internet
**Safety**: 🟡 **User judgment required**
**Common cleanable items**:
- Old installers (.dmg, .pkg)
- Zip archives already extracted
- Temporary downloads
- Duplicate files
**Check before deleting**: Might contain important downloads
### Disk Images (.dmg, .iso)
**What it is**: Mountable disk images, often installers
**Safety**: 🟢 **Safe to delete after installation**
**Typical location**: ~/Downloads
**Cleanup**: Delete .dmg files for already-installed apps
### Archives (.zip, .tar.gz)
**What it is**: Compressed archives
**Safety**: 🟡 **Check if extracted**
**Before deleting**: Verify contents are extracted elsewhere
### Old iOS Backups
**Location**: `~/Library/Application Support/MobileSync/Backup/`
**What it is**: iTunes/Finder iPhone/iPad backups
**Safety**: 🟡 **Caution - backup data**
**Check**:
```bash
ls -lh ~/Library/Application\ Support/MobileSync/Backup/
```
**Cleanup**: Delete old backups via Finder preferences, not manually
### Old Time Machine Local Snapshots
**What it is**: Local Time Machine backups
**Safety**: 🟢 **Safe - macOS manages automatically**
**macOS automatically deletes** these when disk space is low
**Check**:
```bash
tmutil listlocalsnapshots /
```
**Manual cleanup** (rarely needed):
```bash
tmutil deletelocalsnapshots <snapshot_date>
```
## What to NEVER Delete
### User Data Directories
- `~/Documents`
- `~/Desktop`
- `~/Pictures`
- `~/Movies`
- `~/Music`
### System Files
- `/System`
- `/Library/Apple` (unless you know what you're doing)
- `/private/etc`
### Security & Credentials
- `~/.ssh` (SSH keys)
- `~/Library/Keychains` (passwords, certificates)
- Any files containing credentials
### Active Databases
- `*.db`, `*.sqlite` files for running applications
- Docker volumes in active use
## Safety Checklist
Before deleting ANY directory:
1. ✅ Do you know what it is?
2. ✅ Is the application truly uninstalled?
3. ✅ Have you checked if it's in use? (lsof, Activity Monitor)
4. ✅ Do you have a Time Machine backup?
5. ✅ Have you confirmed with the user?
When in doubt, **DON'T DELETE**.
## Recovery Options
### Trash vs. Permanent Deletion
**Use Trash when possible**:
```bash
# Move to trash (recoverable)
osascript -e 'tell app "Finder" to move POSIX file "/path/to/file" to trash'
```
**Permanent deletion**:
```bash
# Cannot be recovered without Time Machine
rm -rf /path/to/file
```
### Time Machine
If you deleted something important:
1. Open Time Machine
2. Navigate to parent directory
3. Select date before deletion
4. Restore
### File Recovery Tools
If no Time Machine backup:
- Disk Drill (commercial)
- PhotoRec (free, for photos)
- TestDisk (free, for files)
**Note**: Success rate depends on how recently deleted and disk usage since deletion.

View File

@@ -0,0 +1,304 @@
# Mole Integration Guide
How to integrate [Mole](https://github.com/tw93/Mole) with the macOS Cleaner skill.
## About Mole
**Mole** is a visual macOS disk cleanup tool with a native macOS interface. It provides:
- Visual disk usage analysis
- One-click cleanup for common targets
- Safe deletion with preview
- Native macOS design
**Repository**: https://github.com/tw93/Mole
## When to Recommend Mole
Suggest Mole to users in these scenarios:
### 1. User Prefers Visual Interface
```
User: "I prefer clicking buttons rather than running commands"
```
**Response**:
```
I recommend using Mole alongside these scripts:
1. Use the analysis scripts to understand what's using space
2. Install Mole for visual cleanup: https://github.com/tw93/Mole
3. Use Mole's GUI to execute cleanup with visual confirmation
Would you like me to guide you through the analysis first?
```
### 2. Complex Cleanup Needs
```
User: "I have lots of cache files and don't want to run commands for each"
```
**Response**:
```
Mole can help with batch cleanup. It provides visual categories:
- System caches
- Application caches
- Log files
- Trash
Install Mole and you can review and clean multiple categories at once.
```
### 3. Ongoing Maintenance
```
User: "I want to clean my Mac regularly"
```
**Response**:
```
For regular maintenance, I recommend:
1. Keep Mole installed for weekly quick cleanups
2. Use our analysis scripts monthly for deep analysis
3. Use safe_delete.py for specific files/folders
This hybrid approach gives you both convenience and precision.
```
## Installation
### Check if Mole is Installed
```bash
if [ -d "/Applications/Mole.app" ]; then
echo "✅ Mole is installed"
open -a Mole
else
echo "💡 Mole is not installed"
echo " Install from: https://github.com/tw93/Mole"
fi
```
### Installation Methods
**Method 1: Download from GitHub Releases**
```bash
# Guide user to:
# 1. Visit https://github.com/tw93/Mole/releases
# 2. Download latest .dmg file
# 3. Open .dmg and drag Mole.app to /Applications
```
**Method 2: Build from Source** (if user is developer)
```bash
git clone https://github.com/tw93/Mole.git
cd Mole
# Follow build instructions in README
```
## Workflow Integration
### Hybrid Workflow: Scripts + Mole
**Best practice**: Use both tools for their strengths.
#### Step 1: Analysis with Scripts
Run comprehensive analysis:
```bash
# System analysis
python3 scripts/analyze_caches.py
python3 scripts/analyze_large_files.py --threshold 100
python3 scripts/find_app_remnants.py
# Developer analysis (if applicable)
python3 scripts/analyze_dev_env.py
```
This gives detailed reports with safety categorization.
#### Step 2: Review Findings
Present findings to user in readable format (see SKILL.md Step 4).
#### Step 3: Execute Cleanup
For different types of cleanup:
**Option A: Use Mole** (for batch operations)
- System caches: Use Mole's "System" category
- Application caches: Use Mole's "Applications" category
- Trash: Use Mole's "Trash" feature
**Option B: Use Scripts** (for precision)
- Large files: Use `safe_delete.py` with specific paths
- Application remnants: Use `safe_delete.py` with confirmed orphans
- Dev environment: Run cleanup commands directly
**Option C: Manual** (for sensitive items)
- Guide user to review in Finder
- User deletes manually
### Example Integrated Session
```markdown
🔍 Analysis Results
I've analyzed your Mac and found:
- System caches: 45 GB (safe to clean)
- Large files: 38 GB (need review)
- App remnants: 8 GB (medium confidence)
- Docker: 25 GB (requires caution)
Recommended cleanup approach:
1. **Use Mole for safe batch cleanup** (45 GB)
- Open Mole
- Select "System Caches"
- Click "Clean"
- This will clear ~/Library/Caches safely
2. **Use scripts for large file review** (38 GB)
- I found 20 large files >100MB
- Let me show you the list
- We'll use safe_delete.py to delete selected files
3. **Manual review for app remnants** (8 GB)
- 5 folders for possibly uninstalled apps
- Please verify these apps are truly gone:
- Adobe Creative Cloud (3 GB)
- Old Xcode version (2 GB)
- ...
4. **Manual Docker cleanup** (25 GB)
- Requires technical review
- I'll guide you through checking volumes
Shall we proceed with step 1 using Mole?
```
## Mole Feature Mapping
Map Mole's features to our script capabilities:
| Mole Feature | Script Equivalent | Use Case |
|--------------|-------------------|----------|
| System Caches | `analyze_caches.py --user-only` | Quick cache cleanup |
| Application Caches | `analyze_caches.py` | Per-app cache analysis |
| Large Files | `analyze_large_files.py` | Find space hogs |
| Trash | N/A (Finder) | Empty trash |
| Duplicate Files | Manual `fdupes` | Find duplicates |
**Mole's advantages**:
- Visual representation
- One-click cleanup
- Native macOS integration
**Scripts' advantages**:
- Developer-specific tools (Docker, npm, pip)
- Application remnant detection
- Detailed categorization and safety notes
- Batch operations with confirmation
## Coordinated Cleanup Strategy
### For Non-Technical Users
1. **Install Mole** - Primary cleanup tool
2. **Keep scripts** - For occasional deep analysis
3. **Workflow**:
- Monthly: Run `analyze_caches.py` to see what's using space
- Use Mole to execute cleanup
- Special cases: Use scripts
### For Technical Users / Developers
1. **Keep both** - Mole for quick cleanup, scripts for precision
2. **Workflow**:
- Weekly: Mole for routine cache cleanup
- Monthly: Full script analysis for deep cleaning
- As needed: Script-based cleanup for dev environment
### For Power Users
1. **Scripts only** - Full control and automation
2. **Workflow**:
- Schedule analysis scripts with cron/launchd
- Review reports
- Execute cleanup with `safe_delete.py` or direct commands
## Limitations & Complementary Use
### What Mole Does Well
✅ Visual disk usage analysis
✅ Safe cache cleanup
✅ User-friendly interface
✅ Quick routine maintenance
### What Mole Doesn't Do (Use Scripts For)
❌ Docker cleanup
❌ Homebrew cache (command-line only)
❌ npm/pip cache
❌ Application remnant detection with confidence levels
❌ Large .git directory detection
❌ Development environment analysis
### Recommended Approach
**Use Mole for**: 80% of routine cleanup needs
**Use Scripts for**: 20% of specialized/technical cleanup needs
## Troubleshooting
### Mole Not Opening
```bash
# Check if Mole is installed
ls -l /Applications/Mole.app
# Try opening from command line (see error messages)
open -a Mole
# If not installed
echo "Download from: https://github.com/tw93/Mole/releases"
```
### Mole Shows Different Numbers than Scripts
**Explanation**:
- Mole uses different calculation methods
- Scripts use `du` command (more accurate for directory sizes)
- Both are valid, differences typically <5%
**Not a problem**: Use Mole's numbers for decisions
### Mole Can't Delete Some Caches
**Reason**: Permission issues (some caches are protected)
**Solution**:
1. Use scripts with sudo for system caches
2. Or manually delete in Finder with authentication
## Summary
**Best Practice**: Use both tools
- **Mole**: Visual cleanup, routine maintenance, user-friendly
- **Scripts**: Deep analysis, developer tools, precise control
**Workflow**:
1. Analyze with scripts (comprehensive report)
2. Execute with Mole (safe and visual) OR scripts (precise and technical)
3. Maintain with Mole (weekly/monthly routine)
This combination provides the best user experience for macOS cleanup.

View File

@@ -0,0 +1,474 @@
# Safety Rules for macOS Cleanup
Critical safety guidelines to prevent data loss and system damage.
## Golden Rules
### Rule 1: Never Delete Without Confirmation
**ALWAYS** ask user before deleting ANY file or directory.
**Bad**:
```python
shutil.rmtree(cache_dir) # Immediately deletes
```
**Good**:
```python
if confirm_delete(cache_dir, size, description):
shutil.rmtree(cache_dir)
else:
print("Skipped")
```
### Rule 2: Explain Before Deleting
Users should understand:
- **What** is being deleted
- **Why** it's safe (or not safe)
- **Impact** of deletion
- **Recoverability** (can it be restored?)
### Rule 3: When in Doubt, Don't Delete
If uncertain about safety: **DON'T DELETE**.
Ask user to verify instead.
### Rule 4: Suggest Backups for Large Deletions
Before deleting >10 GB, recommend Time Machine backup.
### Rule 5: Use Trash When Possible
Prefer moving to Trash over permanent deletion:
```bash
# Recoverable
osascript -e 'tell app "Finder" to move POSIX file "/path/to/file" to trash'
# Permanent (use only when confirmed safe)
rm -rf /path/to/file
```
## Never Delete These
### System Directories
| Path | Why | Impact if Deleted |
|------|-----|-------------------|
| `/System` | macOS core | System unbootable |
| `/Library/Apple` | Apple frameworks | Apps won't launch |
| `/private/etc` | System config | System unstable |
| `/private/var/db` | System databases | System unstable |
| `/usr` | Unix utilities | Commands won't work |
| `/bin`, `/sbin` | System binaries | System unusable |
### User Data
| Path | Why | Impact if Deleted |
|------|-----|-------------------|
| `~/Documents` | User documents | Data loss |
| `~/Desktop` | User files | Data loss |
| `~/Pictures` | Photos | Data loss |
| `~/Movies` | Videos | Data loss |
| `~/Music` | Music library | Data loss |
| `~/Downloads` | May contain important files | Potential data loss |
### Security & Credentials
| Path | Why | Impact if Deleted |
|------|-----|-------------------|
| `~/.ssh` | SSH keys | Cannot access servers |
| `~/Library/Keychains` | Passwords, certificates | Cannot access accounts/services |
| Any file with "credential", "password", "key" in name | Security data | Cannot authenticate |
### Active Databases
| Pattern | Why | Impact if Deleted |
|---------|-----|-------------------|
| `*.db`, `*.sqlite`, `*.sqlite3` | Application databases | App data loss |
| Any database file for running app | Active data | Data corruption |
### Running Applications
| Path | Why | Impact if Deleted |
|------|-----|-------------------|
| `/Applications` | Installed apps | Apps won't launch |
| `~/Applications` | User-installed apps | Apps won't launch |
| Files in use (check with `lsof`) | Currently open | App crash, data corruption |
## Require Extra Confirmation
### Large Deletions
**Threshold**: >10 GB
**Action**: Warn user and suggest Time Machine backup
**Example**:
```
⚠️ This operation will delete 45 GB of data.
💡 Recommendation:
Create a Time Machine backup first.
Check last backup:
tmutil latestbackup
Create backup now:
tmutil startbackup
Proceed without backup? [y/N]:
```
### System-Wide Caches
**Paths**: `/Library/Caches`, `/var/log`
**Action**: Require manual sudo command (don't execute directly)
**Example**:
```
⚠️ This operation requires administrator privileges.
Please run this command manually:
sudo rm -rf /Library/Caches/*
⚠️ You will be asked for your password.
```
**Reason**:
- Requires elevated privileges
- User should be aware of system-wide impact
- Audit trail (user types password)
### Docker Volumes
**Action**: Always list volumes before cleanup
**Example**:
```
⚠️ Docker cleanup may remove important data.
Current volumes:
postgres_data (1.2 GB) - May contain database
redis_data (500 MB) - May contain cache
app_uploads (3 GB) - May contain user files
Review each volume:
docker volume inspect <volume_name>
Proceed with cleanup? [y/N]:
```
### Application Preferences
**Path**: `~/Library/Preferences/*.plist`
**Action**: Warn that app will reset to defaults
**Example**:
```
⚠️ Deleting preferences will reset the app to defaults.
Impact:
- All settings will be lost
- Custom configurations will be reset
- May need to re-enter license keys
Only delete if:
- App is misbehaving (troubleshooting)
- App is confirmed uninstalled
Proceed? [y/N]:
```
## Safety Checks Before Deletion
### Check 1: Path Exists
```python
if not os.path.exists(path):
print(f"❌ Path does not exist: {path}")
return False
```
### Check 2: Not a System Path
```python
system_paths = [
'/System', '/Library/Apple', '/private/etc',
'/usr', '/bin', '/sbin', '/private/var/db'
]
for sys_path in system_paths:
if path.startswith(sys_path):
print(f"❌ Cannot delete system path: {path}")
return False
```
### Check 3: Not User Data
```python
user_data_paths = [
'~/Documents', '~/Desktop', '~/Pictures',
'~/Movies', '~/Music', '~/.ssh'
]
expanded_path = os.path.expanduser(path)
for data_path in user_data_paths:
if expanded_path.startswith(os.path.expanduser(data_path)):
print(f"⚠️ This is a user data directory: {path}")
print(" Are you ABSOLUTELY sure? [type 'DELETE' to confirm]:")
response = input().strip()
if response != 'DELETE':
return False
```
### Check 4: Not in Use
```python
def is_in_use(path):
"""Check if file/directory is in use."""
try:
result = subprocess.run(
['lsof', path],
capture_output=True,
text=True
)
# If lsof finds processes using the file, returncode is 0
if result.returncode == 0:
return True
return False
except:
return False # Assume not in use if check fails
if is_in_use(path):
print(f"⚠️ Warning: {path} is currently in use")
print(" Close the application first, then try again.")
return False
```
### Check 5: Permissions
```python
def can_delete(path):
"""Check if we have permission to delete."""
try:
# Check parent directory write permission
parent = os.path.dirname(path)
return os.access(parent, os.W_OK)
except:
return False
if not can_delete(path):
print(f"❌ No permission to delete: {path}")
print(" You may need sudo, but be careful!")
return False
```
## Safe Deletion Workflow
```python
def safe_delete(path, size, description):
"""
Safe deletion workflow with all checks.
Args:
path: Path to delete
size: Size in bytes
description: Human-readable description
Returns:
(success, message)
"""
# Safety checks
if not os.path.exists(path):
return (False, "Path does not exist")
if is_system_path(path):
return (False, "Cannot delete system path")
if is_user_data(path):
if not extra_confirm(path):
return (False, "User cancelled")
if is_in_use(path):
return (False, "Path is in use")
if not can_delete(path):
return (False, "No permission")
# Backup warning for large deletions
if size > 10 * 1024 * 1024 * 1024: # 10 GB
if not confirm_large_deletion(size):
return (False, "User cancelled")
# Final confirmation
if not confirm_delete(path, size, description):
return (False, "User cancelled")
# Execute deletion
try:
if os.path.isfile(path):
os.unlink(path)
else:
shutil.rmtree(path)
return (True, f"Deleted successfully ({format_size(size)} freed)")
except Exception as e:
return (False, f"Deletion failed: {str(e)}")
```
## Error Handling
### Permission Denied
```python
except PermissionError:
print(f"❌ Permission denied: {path}")
print(" Try running with sudo (use caution!)")
```
### Operation Not Permitted (SIP)
```python
# macOS System Integrity Protection blocks some deletions
except OSError as e:
if e.errno == 1: # Operation not permitted
print(f"❌ System Integrity Protection prevents deletion: {path}")
print(" This is a protected system file.")
print(" Do NOT attempt to bypass SIP unless you know what you're doing.")
```
### Path Too Long
```python
except OSError as e:
if e.errno == 63: # File name too long
print(f"⚠️ Path too long, trying alternative method...")
# Try using find + rm
```
## Recovery Options
### If User Accidentally Confirmed
**Immediate action**: Check Trash first
```bash
# Files may be in Trash
ls -lh ~/.Trash
```
**Next**: Time Machine
```bash
# Open Time Machine to date before deletion
tmutil browse
```
**Last resort**: File recovery tools
- Disk Drill (commercial)
- PhotoRec (free)
- TestDisk (free)
**Note**: Success rate depends on:
- How recently deleted
- How much disk activity since deletion
- Whether SSD (TRIM) or HDD
### Preventing Accidents
1. **Use Trash instead of rm** when possible
2. **Require Time Machine backup** for >10 GB deletions
3. **Test on small items first** before batch operations
4. **Show dry-run results** before actual deletion
## Red Flags to Watch For
### User Requests
If user asks to:
- "Delete everything in ~/Library"
- "Clear all caches including system"
- "Delete all .log files on the entire system"
- "Remove all databases"
**Response**:
```
⚠️ This request is too broad and risky.
Let me help you with a safer approach:
1. Run analysis to identify specific targets
2. Review each category
3. Delete selectively with confirmation
This prevents accidental data loss.
```
### Script Behavior
If script is about to:
- Delete >100 GB at once
- Delete entire directory trees without listing contents
- Run `rm -rf /` or similar dangerous commands
- Delete from system paths
**Action**: STOP and ask for confirmation
## Testing Guidelines
### Before Packaging
Test safety checks:
1. ✅ Attempt to delete system path → Should reject
2. ✅ Attempt to delete user data → Should require extra confirmation
3. ✅ Attempt to delete in-use file → Should warn
4. ✅ Attempt to delete without permission → Should fail gracefully
5. ✅ Large deletion → Should suggest backup
### In Production
Always:
- Start with smallest items
- Confirm results after each deletion
- Monitor disk space before/after
- Ask user to verify important apps still work
## Summary
### Conservative Approach
When implementing cleanup:
1. **Assume danger** until proven safe
2. **Explain everything** to user
3. **Confirm each step**
4. **Suggest backups** for large operations
5. **Use Trash** when possible
6. **Test thoroughly** before packaging
### Remember
> "It's better to leave 1 GB of unnecessary files than to delete 1 MB of important data."
User trust is fragile. One bad deletion loses it forever.
### Final Checklist
Before any deletion:
- [ ] Path is verified to exist
- [ ] Path is not a system path
- [ ] Path is not user data (or extra confirmed)
- [ ] Path is not in use
- [ ] User has been informed of impact
- [ ] User has explicitly confirmed
- [ ] Backup suggested for large deletions
- [ ] Error handling in place
- [ ] Recovery options documented
Only then: proceed with deletion.

View File

@@ -0,0 +1,211 @@
#!/usr/bin/env python3
"""
Analyze macOS cache directories and categorize them by size and safety.
Usage:
python3 analyze_caches.py [--user-only] [--min-size SIZE]
Options:
--user-only Only scan user caches (~/Library/Caches), skip system caches
--min-size Minimum size in MB to report (default: 10)
"""
import os
import sys
import subprocess
import argparse
from pathlib import Path
def get_dir_size(path):
"""
Get directory size using du command.
Args:
path: Directory path
Returns:
Size in bytes, or 0 if error
"""
try:
result = subprocess.run(
['du', '-sk', path],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
# du -sk returns size in KB
size_kb = int(result.stdout.split()[0])
return size_kb * 1024 # Convert to bytes
return 0
except (subprocess.TimeoutExpired, ValueError, IndexError):
return 0
def format_size(bytes_size):
"""Convert bytes to human-readable format."""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} PB"
def analyze_cache_dir(base_path, min_size_bytes):
"""
Analyze a cache directory and list subdirectories by size.
Args:
base_path: Path to cache directory
min_size_bytes: Minimum size to report
Returns:
List of (name, path, size_bytes) tuples
"""
if not os.path.exists(base_path):
return []
results = []
try:
for entry in os.scandir(base_path):
if entry.is_dir():
size = get_dir_size(entry.path)
if size >= min_size_bytes:
results.append((entry.name, entry.path, size))
except PermissionError:
print(f"⚠️ Permission denied: {base_path}", file=sys.stderr)
return []
# Sort by size descending
results.sort(key=lambda x: x[2], reverse=True)
return results
def categorize_safety(name):
"""
Categorize cache safety based on name patterns.
Returns:
('safe'|'check'|'keep', reason)
"""
name_lower = name.lower()
# Known safe to delete
safe_patterns = [
'chrome', 'firefox', 'safari', 'edge', # Browsers
'spotify', 'slack', 'discord', # Communication
'pip', 'npm', 'homebrew', # Package managers
'temp', 'tmp', 'cache' # Generic temp
]
if any(pattern in name_lower for pattern in safe_patterns):
return ('safe', 'Application regenerates cache automatically')
# Check before deleting
check_patterns = [
'xcode', 'android', # IDEs (may slow next launch)
'jetbrains', 'vscode',
'docker' # May contain important build cache
]
if any(pattern in name_lower for pattern in check_patterns):
return ('check', 'May slow down next application launch')
# Default: check first
return ('check', 'Unknown application, verify before deleting')
def main():
parser = argparse.ArgumentParser(
description='Analyze macOS cache directories'
)
parser.add_argument(
'--user-only',
action='store_true',
help='Only scan user caches (skip system caches)'
)
parser.add_argument(
'--min-size',
type=int,
default=10,
help='Minimum size in MB to report (default: 10)'
)
args = parser.parse_args()
min_size_bytes = args.min_size * 1024 * 1024 # Convert MB to bytes
print("🔍 Analyzing macOS Cache Directories")
print("=" * 50)
# User caches
user_cache_path = os.path.expanduser('~/Library/Caches')
print(f"\n📂 User Caches: {user_cache_path}")
print("-" * 50)
user_caches = analyze_cache_dir(user_cache_path, min_size_bytes)
total_user = 0
if user_caches:
print(f"{'Application':<40} {'Size':<12} {'Safety'}")
print("-" * 70)
for name, path, size in user_caches:
safety, reason = categorize_safety(name)
safety_icon = {'safe': '🟢', 'check': '🟡', 'keep': '🔴'}[safety]
print(f"{name:<40} {format_size(size):<12} {safety_icon}")
total_user += size
print("-" * 70)
print(f"{'Total':<40} {format_size(total_user):<12}")
else:
print("No cache directories found above minimum size.")
# User logs
user_log_path = os.path.expanduser('~/Library/Logs')
if os.path.exists(user_log_path):
log_size = get_dir_size(user_log_path)
if log_size >= min_size_bytes:
print(f"\n📝 User Logs: {user_log_path}")
print(f" Size: {format_size(log_size)} 🟢 Safe to delete")
total_user += log_size
# System caches (if not --user-only)
if not args.user_only:
print(f"\n\n📂 System Caches: /Library/Caches")
print("-" * 50)
print("⚠️ Requires administrator privileges to delete")
system_cache_path = '/Library/Caches'
system_caches = analyze_cache_dir(system_cache_path, min_size_bytes)
total_system = 0
if system_caches:
print(f"{'Application':<40} {'Size':<12}")
print("-" * 70)
for name, path, size in system_caches[:10]: # Top 10 only
print(f"{name:<40} {format_size(size):<12}")
total_system += size
if len(system_caches) > 10:
print(f"... and {len(system_caches) - 10} more")
print("-" * 70)
print(f"{'Total':<40} {format_size(total_system):<12}")
else:
print("No cache directories found above minimum size.")
# Summary
print("\n" + "=" * 50)
print("📊 Summary")
print("=" * 50)
print(f"Total User Caches: {format_size(total_user)}")
if not args.user_only:
print(f"Total System Caches: {format_size(total_system)}")
print(f"Combined Total: {format_size(total_user + total_system)}")
print("\n💡 Next Steps:")
print(" 1. Review the list above")
print(" 2. Identify caches marked 🟢 (safe to delete)")
print(" 3. For 🟡 items, verify the application is not running")
print(" 4. Use safe_delete.py for interactive cleanup")
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,307 @@
#!/usr/bin/env python3
"""
Analyze development environment and find cleanable resources.
Checks:
- Docker (images, containers, volumes, build cache)
- Homebrew cache
- npm cache
- pip cache
- Old .git directories in archived projects
Usage:
python3 analyze_dev_env.py
"""
import os
import sys
import subprocess
import json
from pathlib import Path
def format_size(bytes_size):
"""Convert bytes to human-readable format."""
if bytes_size is None:
return "Unknown"
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} PB"
def run_command(cmd):
"""Run command and return output, or None if error."""
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
return result.stdout.strip()
return None
except (subprocess.TimeoutExpired, FileNotFoundError):
return None
def get_dir_size(path):
"""Get directory size using du command."""
output = run_command(['du', '-sk', path])
if output:
try:
size_kb = int(output.split()[0])
return size_kb * 1024 # Convert to bytes
except (ValueError, IndexError):
pass
return 0
def check_docker():
"""Check Docker resources."""
print("\n🐳 Docker Resources")
print("=" * 50)
# Check if Docker is installed
if not run_command(['which', 'docker']):
print(" Docker not installed or not in PATH")
return 0
# Check if Docker daemon is running
if not run_command(['docker', 'info']):
print(" Docker daemon not running")
return 0
total_size = 0
# Images
images_output = run_command(['docker', 'images', '-q'])
if images_output:
image_count = len(images_output.split('\n'))
print(f"\n📦 Images: {image_count}")
# Get size estimate
system_output = run_command(['docker', 'system', 'df', '--format', '{{json .}}'])
if system_output:
for line in system_output.split('\n'):
try:
data = json.loads(line)
if data.get('Type') == 'Images':
size_str = data.get('Size', '')
# Parse size (format like "1.2GB")
if 'GB' in size_str:
size = float(size_str.replace('GB', '')) * 1024 * 1024 * 1024
elif 'MB' in size_str:
size = float(size_str.replace('MB', '')) * 1024 * 1024
else:
size = 0
print(f" Total size: {format_size(size)}")
total_size += size
except (json.JSONDecodeError, ValueError):
pass
# Containers
containers_output = run_command(['docker', 'ps', '-a', '-q'])
if containers_output:
container_count = len(containers_output.split('\n'))
stopped = run_command(['docker', 'ps', '-a', '-f', 'status=exited', '-q'])
stopped_count = len(stopped.split('\n')) if stopped else 0
print(f"\n📦 Containers: {container_count} total, {stopped_count} stopped")
# Volumes
volumes_output = run_command(['docker', 'volume', 'ls', '-q'])
if volumes_output:
volume_count = len(volumes_output.split('\n'))
print(f"\n📦 Volumes: {volume_count}")
# List volumes
for volume in volumes_output.split('\n')[:5]: # Show first 5
inspect = run_command(['docker', 'volume', 'inspect', volume])
print(f" - {volume}")
if volume_count > 5:
print(f" ... and {volume_count - 5} more")
# Build cache
buildx_output = run_command(['docker', 'buildx', 'du'])
if buildx_output and 'Total:' in buildx_output:
print(f"\n📦 Build Cache:")
for line in buildx_output.split('\n'):
if 'Total:' in line:
print(f" {line}")
print(f"\n💡 Cleanup command: docker system prune -a --volumes")
print(f" ⚠️ Warning: This will remove ALL unused Docker resources")
return total_size
def check_homebrew():
"""Check Homebrew cache."""
print("\n🍺 Homebrew")
print("=" * 50)
if not run_command(['which', 'brew']):
print(" Homebrew not installed")
return 0
cache_path = run_command(['brew', '--cache'])
if cache_path and os.path.exists(cache_path):
size = get_dir_size(cache_path)
print(f" Cache location: {cache_path}")
print(f" Cache size: {format_size(size)}")
print(f"\n💡 Cleanup command: brew cleanup -s")
return size
return 0
def check_npm():
"""Check npm cache."""
print("\n📦 npm")
print("=" * 50)
if not run_command(['which', 'npm']):
print(" npm not installed")
return 0
cache_path = run_command(['npm', 'config', 'get', 'cache'])
if cache_path and cache_path != 'undefined' and os.path.exists(cache_path):
size = get_dir_size(cache_path)
print(f" Cache location: {cache_path}")
print(f" Cache size: {format_size(size)}")
print(f"\n💡 Cleanup command: npm cache clean --force")
return size
return 0
def check_pip():
"""Check pip cache."""
print("\n🐍 pip")
print("=" * 50)
# Try pip3 first
pip_cmd = 'pip3' if run_command(['which', 'pip3']) else 'pip'
if not run_command(['which', pip_cmd]):
print(" pip not installed")
return 0
cache_dir = run_command([pip_cmd, 'cache', 'dir'])
if cache_dir and os.path.exists(cache_dir):
size = get_dir_size(cache_dir)
print(f" Cache location: {cache_dir}")
print(f" Cache size: {format_size(size)}")
print(f"\n💡 Cleanup command: {pip_cmd} cache purge")
return size
return 0
def check_old_git_repos():
"""Find large .git directories in archived projects."""
print("\n📁 Old Git Repositories")
print("=" * 50)
home = Path.home()
common_project_dirs = [
home / 'Projects',
home / 'workspace',
home / 'dev',
home / 'src',
home / 'code'
]
git_repos = []
total_size = 0
for project_dir in common_project_dirs:
if not project_dir.exists():
continue
# Find .git directories
try:
result = subprocess.run(
['find', str(project_dir), '-name', '.git', '-type', 'd', '-maxdepth', 3],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
for git_path in result.stdout.strip().split('\n'):
if git_path:
size = get_dir_size(git_path)
if size > 10 * 1024 * 1024: # > 10 MB
git_repos.append((git_path, size))
total_size += size
except subprocess.TimeoutExpired:
continue
if git_repos:
# Sort by size
git_repos.sort(key=lambda x: x[1], reverse=True)
print(f" Found {len(git_repos)} .git directories > 10 MB")
print(f"\n Top 10 largest:")
for path, size in git_repos[:10]:
# Get parent directory name (project name)
project_name = Path(path).parent.name
print(f" - {project_name:<30} {format_size(size)}")
print(f"\n Total: {format_size(total_size)}")
print(f"\n💡 If these are archived projects, consider:")
print(f" 1. Delete .git history: rm -rf <project>/.git")
print(f" 2. Or compress entire project: tar -czf archive.tar.gz <project>")
else:
print(" No large .git directories found in common project locations")
return total_size
def main():
print("🔍 Development Environment Analysis")
print("=" * 50)
total_savings = 0
# Check each component
docker_size = check_docker()
brew_size = check_homebrew()
npm_size = check_npm()
pip_size = check_pip()
git_size = check_old_git_repos()
# Summary
print("\n\n📊 Summary")
print("=" * 50)
if docker_size:
print(f"Docker: {format_size(docker_size)}")
total_savings += docker_size
if brew_size:
print(f"Homebrew cache: {format_size(brew_size)}")
total_savings += brew_size
if npm_size:
print(f"npm cache: {format_size(npm_size)}")
total_savings += npm_size
if pip_size:
print(f"pip cache: {format_size(pip_size)}")
total_savings += pip_size
if git_size:
print(f"Old .git repos: {format_size(git_size)}")
total_savings += git_size
print("-" * 50)
print(f"Potential savings: {format_size(total_savings)}")
print("\n💡 Next Steps:")
print(" 1. Review Docker volumes before cleanup (may contain data)")
print(" 2. Package manager caches are safe to delete")
print(" 3. For .git directories, ensure project is truly archived")
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,241 @@
#!/usr/bin/env python3
"""
Find large files on macOS and categorize them.
Usage:
python3 analyze_large_files.py [--threshold SIZE] [--path PATH] [--limit N]
Options:
--threshold Minimum file size in MB (default: 100)
--path Path to search (default: ~)
--limit Maximum number of results (default: 50)
"""
import os
import sys
import argparse
import subprocess
from pathlib import Path
def format_size(bytes_size):
"""Convert bytes to human-readable format."""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} PB"
def categorize_file(path):
"""
Categorize file by type and suggest safety.
Returns:
(category, icon, safety_note)
"""
suffix = path.suffix.lower()
# Video files
video_exts = {'.mp4', '.mov', '.avi', '.mkv', '.m4v', '.flv', '.wmv'}
if suffix in video_exts:
return ('Video', '🎬', 'Review and archive to external storage')
# Archive files
archive_exts = {'.zip', '.tar', '.gz', '.bz2', '.7z', '.rar', '.dmg'}
if suffix in archive_exts:
return ('Archive', '📦', 'Extract if needed, then delete archive')
# Disk images
disk_exts = {'.iso', '.img', '.toast'}
if suffix in disk_exts:
return ('Disk Image', '💿', 'Delete after installation/use')
# Database files
db_exts = {'.db', '.sqlite', '.sqlite3', '.sql'}
if suffix in db_exts:
return ('Database', '🗄️', '⚠️ Verify not in use before deleting')
# Data files
data_exts = {'.csv', '.json', '.xml', '.parquet', '.arrow'}
if suffix in data_exts:
return ('Data File', '📊', 'Archive or compress if historical data')
# Log files
if suffix == '.log' or 'log' in path.name.lower():
return ('Log File', '📝', 'Safe to delete old logs')
# Build artifacts
build_patterns = ['.o', '.a', '.so', '.dylib', '.framework']
if suffix in build_patterns:
return ('Build Artifact', '🔨', 'Safe to delete, rebuild will regenerate')
# Virtual machine images
vm_exts = {'.vmdk', '.vdi', '.qcow2', '.vhd'}
if suffix in vm_exts:
return ('VM Image', '💻', '⚠️ Contains VM data, verify before deleting')
# Other
return ('Other', '📄', 'Review before deleting')
def find_large_files(search_path, threshold_bytes, limit):
"""
Find files larger than threshold using find command.
Args:
search_path: Path to search
threshold_bytes: Minimum size in bytes
limit: Maximum results
Returns:
List of (path, size_bytes) tuples
"""
# Convert bytes to 512-byte blocks (find -size uses 512-byte blocks)
threshold_blocks = threshold_bytes // 512
# Exclude common directories to avoid
exclude_dirs = [
'.Trash',
'Library/Caches',
'Library/Application Support/MobileSync', # iOS backups
'.git',
'node_modules',
'__pycache__'
]
# Build find command
cmd = ['find', search_path, '-type', 'f', '-size', f'+{threshold_blocks}']
# Add exclusions
for exclude in exclude_dirs:
cmd.extend(['-not', '-path', f'*/{exclude}/*'])
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=120
)
if result.returncode != 0:
print(f"⚠️ Warning: find command had errors", file=sys.stderr)
files = []
for line in result.stdout.strip().split('\n'):
if not line:
continue
try:
path = Path(line)
if path.exists():
size = path.stat().st_size
files.append((path, size))
except (OSError, PermissionError):
continue
# Sort by size descending
files.sort(key=lambda x: x[1], reverse=True)
return files[:limit]
except subprocess.TimeoutExpired:
print("⚠️ Search timed out, showing partial results", file=sys.stderr)
return []
def main():
parser = argparse.ArgumentParser(
description='Find large files on macOS'
)
parser.add_argument(
'--threshold',
type=int,
default=100,
help='Minimum file size in MB (default: 100)'
)
parser.add_argument(
'--path',
default=os.path.expanduser('~'),
help='Path to search (default: ~)'
)
parser.add_argument(
'--limit',
type=int,
default=50,
help='Maximum number of results (default: 50)'
)
args = parser.parse_args()
threshold_bytes = args.threshold * 1024 * 1024
search_path = os.path.expanduser(args.path)
print(f"🔍 Searching for files larger than {args.threshold} MB")
print(f"📂 Search path: {search_path}")
print("=" * 80)
print("This may take a few minutes...\n")
large_files = find_large_files(search_path, threshold_bytes, args.limit)
if not large_files:
print("✅ No large files found above the threshold.")
return 0
print(f"\n📦 Found {len(large_files)} large files")
print("=" * 80)
print(f"{'#':<4} {'Size':<12} {'Type':<12} {'Location'}")
print("-" * 80)
# Group by category
by_category = {}
total_size = 0
for i, (path, size) in enumerate(large_files, 1):
category, icon, note = categorize_file(path)
# Shorten path for display
try:
rel_path = path.relative_to(Path.home())
display_path = f"~/{rel_path}"
except ValueError:
display_path = str(path)
# Truncate long paths
if len(display_path) > 45:
display_path = display_path[:42] + "..."
print(f"{i:<4} {format_size(size):<12} {icon} {category:<10} {display_path}")
# Track by category
if category not in by_category:
by_category[category] = {'count': 0, 'size': 0, 'note': note}
by_category[category]['count'] += 1
by_category[category]['size'] += size
total_size += size
print("-" * 80)
print(f"{'Total':<4} {format_size(total_size):<12}")
# Category summary
print("\n\n📊 Breakdown by Category")
print("=" * 80)
for category, data in sorted(
by_category.items(),
key=lambda x: x[1]['size'],
reverse=True
):
print(f"\n{category}")
print(f" Files: {data['count']}")
print(f" Total: {format_size(data['size'])}")
print(f" 💡 {data['note']}")
print("\n\n💡 Next Steps:")
print(" 1. Review the list and identify files you no longer need")
print(" 2. For videos/archives: consider moving to external storage")
print(" 3. For databases/VMs: verify they're not in use")
print(" 4. Use safe_delete.py for interactive cleanup")
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,234 @@
#!/usr/bin/env python3
"""
Generate before/after cleanup reports.
Usage:
# Capture before snapshot
python3 cleanup_report.py --snapshot before
# Capture after snapshot and generate report
python3 cleanup_report.py --snapshot after --compare
"""
import os
import sys
import json
import argparse
import subprocess
from datetime import datetime
from pathlib import Path
def format_size(bytes_size):
"""Convert bytes to human-readable format."""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} PB"
def get_disk_usage():
"""
Get current disk usage.
Returns:
dict with total, used, available, percent
"""
try:
result = subprocess.run(
['df', '-k', '/'],
capture_output=True,
text=True
)
if result.returncode == 0:
lines = result.stdout.strip().split('\n')
if len(lines) >= 2:
# Parse df output
parts = lines[1].split()
total_kb = int(parts[1])
used_kb = int(parts[2])
available_kb = int(parts[3])
percent = int(parts[4].rstrip('%'))
return {
'total': total_kb * 1024,
'used': used_kb * 1024,
'available': available_kb * 1024,
'percent': percent,
'timestamp': datetime.now().isoformat()
}
except:
pass
return None
def save_snapshot(name):
"""Save disk usage snapshot to file."""
snapshot_dir = Path.home() / '.macos-cleaner'
snapshot_dir.mkdir(exist_ok=True)
snapshot_file = snapshot_dir / f'{name}.json'
usage = get_disk_usage()
if usage:
with snapshot_file.open('w') as f:
json.dump(usage, f, indent=2)
print(f"✅ Snapshot saved: {snapshot_file}")
return True
else:
print("❌ Failed to get disk usage")
return False
def load_snapshot(name):
"""Load disk usage snapshot from file."""
snapshot_dir = Path.home() / '.macos-cleaner'
snapshot_file = snapshot_dir / f'{name}.json'
if not snapshot_file.exists():
print(f"❌ Snapshot not found: {snapshot_file}")
return None
with snapshot_file.open('r') as f:
return json.load(f)
def generate_report(before, after):
"""Generate comparison report."""
print("\n" + "=" * 60)
print("📊 Cleanup Report")
print("=" * 60)
# Time
before_time = datetime.fromisoformat(before['timestamp'])
after_time = datetime.fromisoformat(after['timestamp'])
duration = after_time - before_time
print(f"\nCleanup Duration: {duration}")
print(f"Before: {before_time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"After: {after_time.strftime('%Y-%m-%d %H:%M:%S')}")
# Disk usage comparison
print("\n" + "-" * 60)
print("Disk Usage")
print("-" * 60)
before_used = before['used']
after_used = after['used']
recovered = before_used - after_used
print(f"Before: {format_size(before_used):>12} ({before['percent']}%)")
print(f"After: {format_size(after_used):>12} ({after['percent']}%)")
print("-" * 60)
if recovered > 0:
print(f"✅ Recovered: {format_size(recovered):>12}")
percent_recovered = (recovered / before_used) * 100
print(f" ({percent_recovered:.1f}% of used space)")
elif recovered < 0:
print(f"⚠️ Space increased: {format_size(abs(recovered)):>12}")
print(" (This may be due to system activity during cleanup)")
else:
print("No change in disk usage")
# Available space
print("\n" + "-" * 60)
print("Available Space")
print("-" * 60)
before_avail = before['available']
after_avail = after['available']
gained = after_avail - before_avail
print(f"Before: {format_size(before_avail):>12}")
print(f"After: {format_size(after_avail):>12}")
print("-" * 60)
if gained > 0:
print(f"✅ Gained: {format_size(gained):>12}")
elif gained < 0:
print(f"⚠️ Lost: {format_size(abs(gained)):>12}")
else:
print("No change")
# Recommendations
print("\n" + "=" * 60)
if after['percent'] > 90:
print("⚠️ Warning: Disk is still >90% full")
print("\n💡 Recommendations:")
print(" - Consider moving large files to external storage")
print(" - Review and delete old projects")
print(" - Check for large application data")
elif after['percent'] > 80:
print("⚠️ Disk usage is still high (>80%)")
print("\n💡 Recommendations:")
print(" - Run cleanup again in 1-2 weeks")
print(" - Monitor large file creation")
else:
print("✅ Disk usage is healthy!")
print("\n💡 Maintenance Tips:")
print(" - Run cleanup monthly")
print(" - Empty Trash regularly")
print(" - Clear browser caches weekly")
print("=" * 60)
def main():
parser = argparse.ArgumentParser(
description='Generate cleanup reports'
)
parser.add_argument(
'--snapshot',
choices=['before', 'after'],
required=True,
help='Snapshot type (before or after cleanup)'
)
parser.add_argument(
'--compare',
action='store_true',
help='Compare with before snapshot (use with --snapshot after)'
)
args = parser.parse_args()
if args.snapshot == 'before':
# Save before snapshot
print("📸 Capturing disk usage before cleanup...")
if save_snapshot('before'):
usage = get_disk_usage()
print(f"\nCurrent Usage: {format_size(usage['used'])} ({usage['percent']}%)")
print(f"Available: {format_size(usage['available'])}")
print("\n💡 Run cleanup operations, then:")
print(" python3 cleanup_report.py --snapshot after --compare")
return 0
elif args.snapshot == 'after':
# Save after snapshot
print("📸 Capturing disk usage after cleanup...")
if not save_snapshot('after'):
return 1
if args.compare:
# Load before snapshot and compare
before = load_snapshot('before')
after = load_snapshot('after')
if before and after:
generate_report(before, after)
else:
print("❌ Cannot compare: missing snapshots")
return 1
else:
usage = get_disk_usage()
print(f"\nCurrent Usage: {format_size(usage['used'])} ({usage['percent']}%)")
print(f"Available: {format_size(usage['available'])}")
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,246 @@
#!/usr/bin/env python3
"""
Find orphaned application support files and preferences.
This script identifies directories in ~/Library that may belong to
uninstalled applications.
Usage:
python3 find_app_remnants.py [--min-size SIZE]
Options:
--min-size Minimum size in MB to report (default: 10)
"""
import os
import sys
import subprocess
import argparse
from pathlib import Path
def format_size(bytes_size):
"""Convert bytes to human-readable format."""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} PB"
def get_dir_size(path):
"""Get directory size using du command."""
try:
result = subprocess.run(
['du', '-sk', path],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
size_kb = int(result.stdout.split()[0])
return size_kb * 1024
return 0
except (subprocess.TimeoutExpired, ValueError, IndexError):
return 0
def get_installed_apps():
"""Get list of installed application names."""
apps = set()
# System applications
system_app_dir = Path('/Applications')
if system_app_dir.exists():
for app in system_app_dir.iterdir():
if app.suffix == '.app':
# Remove .app suffix
apps.add(app.stem)
# User applications
user_app_dir = Path.home() / 'Applications'
if user_app_dir.exists():
for app in user_app_dir.iterdir():
if app.suffix == '.app':
apps.add(app.stem)
return apps
def normalize_name(name):
"""
Normalize app name for matching.
Examples:
'Google Chrome' -> 'googlechrome'
'com.apple.Safari' -> 'safari'
"""
# Remove common prefixes
for prefix in ['com.', 'org.', 'net.', 'io.']:
if name.startswith(prefix):
name = name[len(prefix):]
# Remove non-alphanumeric
name = ''.join(c for c in name if c.isalnum())
return name.lower()
def is_likely_orphaned(dir_name, installed_apps):
"""
Check if directory is likely orphaned.
Returns:
(is_orphaned, confidence, reason)
confidence: 'high' | 'medium' | 'low'
"""
norm_dir = normalize_name(dir_name)
# Check exact matches
for app in installed_apps:
norm_app = normalize_name(app)
if norm_app in norm_dir or norm_dir in norm_app:
return (False, None, f"Matches installed app: {app}")
# System/common directories to always keep
system_dirs = {
'apple', 'safari', 'finder', 'mail', 'messages', 'notes',
'photos', 'music', 'calendar', 'contacts', 'reminders',
'preferences', 'cookies', 'webkit', 'coredata',
'cloudkit', 'icloud', 'appstore', 'systemmigration'
}
if any(sys_dir in norm_dir for sys_dir in system_dirs):
return (False, None, "System/built-in application")
# If we get here, likely orphaned
return (True, 'medium', "No matching application found")
def analyze_library_dir(library_path, min_size_bytes, installed_apps):
"""
Analyze a Library subdirectory for orphaned data.
Args:
library_path: Path to scan (e.g., ~/Library/Application Support)
min_size_bytes: Minimum size to report
installed_apps: Set of installed app names
Returns:
List of (name, path, size, confidence, reason) tuples
"""
if not os.path.exists(library_path):
return []
results = []
try:
for entry in os.scandir(library_path):
if entry.is_dir():
size = get_dir_size(entry.path)
if size >= min_size_bytes:
is_orphaned, confidence, reason = is_likely_orphaned(
entry.name,
installed_apps
)
if is_orphaned:
results.append((
entry.name,
entry.path,
size,
confidence,
reason
))
except PermissionError:
print(f"⚠️ Permission denied: {library_path}", file=sys.stderr)
return []
# Sort by size descending
results.sort(key=lambda x: x[2], reverse=True)
return results
def main():
parser = argparse.ArgumentParser(
description='Find orphaned application data'
)
parser.add_argument(
'--min-size',
type=int,
default=10,
help='Minimum size in MB to report (default: 10)'
)
args = parser.parse_args()
min_size_bytes = args.min_size * 1024 * 1024
print("🔍 Searching for Orphaned Application Data")
print("=" * 70)
# Get installed apps
print("Scanning installed applications...")
installed_apps = get_installed_apps()
print(f"Found {len(installed_apps)} installed applications\n")
# Directories to check
library_dirs = {
'Application Support': Path.home() / 'Library' / 'Application Support',
'Containers': Path.home() / 'Library' / 'Containers',
'Preferences': Path.home() / 'Library' / 'Preferences',
'Saved Application State': Path.home() / 'Library' / 'Saved Application State'
}
all_orphans = []
total_size = 0
for category, path in library_dirs.items():
print(f"\n📂 {category}")
print("-" * 70)
orphans = analyze_library_dir(path, min_size_bytes, installed_apps)
if orphans:
print(f"{'Name':<40} {'Size':<12} {'Confidence'}")
print("-" * 70)
for name, full_path, size, confidence, reason in orphans:
conf_icon = {'high': '🔴', 'medium': '🟡', 'low': '🟢'}[confidence]
# Truncate long names
display_name = name if len(name) <= 37 else name[:34] + "..."
print(f"{display_name:<40} {format_size(size):<12} {conf_icon} {confidence}")
all_orphans.append((category, name, full_path, size, confidence, reason))
total_size += size
else:
print("No orphaned data found above minimum size")
# Summary
print("\n\n📊 Summary")
print("=" * 70)
print(f"Total orphaned data found: {len(all_orphans)} items")
print(f"Total size: {format_size(total_size)}")
if all_orphans:
print("\n\n🗑️ Recommended Deletions (Medium/High Confidence)")
print("=" * 70)
for category, name, path, size, confidence, reason in all_orphans:
if confidence in ['medium', 'high']:
print(f"\n{name}")
print(f" Location: {path}")
print(f" Size: {format_size(size)}")
print(f" Reason: {reason}")
print(f" ⚠️ Verify this app is truly uninstalled before deleting")
print("\n\n💡 Next Steps:")
print(" 1. Double-check each item in /Applications and ~/Applications")
print(" 2. Search Spotlight for the application name")
print(" 3. If truly uninstalled, safe to delete with:")
print(" rm -rf '<path>'")
print(" 4. Or use safe_delete.py for interactive cleanup")
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,305 @@
#!/usr/bin/env python3
"""
Interactive safe file/directory deletion with confirmation.
Usage:
python3 safe_delete.py <path1> [path2] [path3] ...
python3 safe_delete.py --batch <file_with_paths>
Options:
--batch FILE Read paths from a file (one per line)
"""
import os
import sys
import shutil
import argparse
import subprocess
from pathlib import Path
def format_size(bytes_size):
"""Convert bytes to human-readable format."""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} PB"
def get_size(path):
"""Get size of file or directory."""
path_obj = Path(path)
if not path_obj.exists():
return 0
if path_obj.is_file():
return path_obj.stat().st_size
elif path_obj.is_dir():
try:
result = subprocess.run(
['du', '-sk', path],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
size_kb = int(result.stdout.split()[0])
return size_kb * 1024
except (subprocess.TimeoutExpired, ValueError, IndexError):
pass
return 0
def get_description(path):
"""Get human-readable description of path."""
path_obj = Path(path)
if not path_obj.exists():
return "Path does not exist"
if path_obj.is_file():
suffix = path_obj.suffix or "file"
return f"File ({suffix})"
elif path_obj.is_dir():
try:
# Count items
items = list(path_obj.iterdir())
return f"Directory ({len(items)} items)"
except PermissionError:
return "Directory (permission denied to list)"
return "Unknown"
def confirm_delete(path, size, description):
"""
Ask user to confirm deletion.
Args:
path: File/directory path
size: Size in bytes
description: What this file/directory is
Returns:
True if user confirms, False otherwise
"""
print(f"\n🗑️ Confirm Deletion")
print("" * 50)
print(f"Path: {path}")
print(f"Size: {format_size(size)}")
print(f"Description: {description}")
# Additional safety check for important paths
path_str = str(path).lower()
danger_patterns = [
'documents', 'desktop', 'pictures', 'movies',
'downloads', 'music', '.ssh', 'credentials'
]
if any(pattern in path_str for pattern in danger_patterns):
print("\n⚠️ WARNING: This path may contain important personal data!")
print(" Consider backing up before deletion.")
response = input("\nDelete this item? [y/N]: ").strip().lower()
return response == 'y'
def batch_confirm(items):
"""
Show all items, ask for batch confirmation.
Args:
items: List of (path, size, description) tuples
Returns:
List of items user approved
"""
print("\n📋 Items to Delete:")
print("" * 70)
print(f"{'#':<4} {'Size':<12} {'Path'}")
print("-" * 70)
for i, (path, size, description) in enumerate(items, 1):
# Truncate long paths
display_path = str(path)
if len(display_path) > 48:
display_path = display_path[:45] + "..."
print(f"{i:<4} {format_size(size):<12} {display_path}")
total_size = sum(item[1] for item in items)
print("-" * 70)
print(f"{'Total':<4} {format_size(total_size):<12}")
print("\nOptions:")
print(" 'all' - Delete all items")
print(" '1,3,5' - Delete specific items by number")
print(" '1-5' - Delete range of items")
print(" 'none' - Cancel (default)")
response = input("\nYour choice: ").strip().lower()
if response == '' or response == 'none':
return []
elif response == 'all':
return items
else:
selected = []
# Parse response
parts = response.replace(' ', '').split(',')
for part in parts:
try:
if '-' in part:
# Range: 1-5
start, end = part.split('-')
start_idx = int(start) - 1
end_idx = int(end) - 1
for i in range(start_idx, end_idx + 1):
if 0 <= i < len(items):
selected.append(items[i])
else:
# Single number
idx = int(part) - 1
if 0 <= idx < len(items):
selected.append(items[idx])
except ValueError:
print(f"⚠️ Ignoring invalid selection: {part}")
continue
return selected
def delete_path(path):
"""
Delete a file or directory.
Returns:
(success, message)
"""
try:
path_obj = Path(path)
if not path_obj.exists():
return (False, "Path does not exist")
if path_obj.is_file():
path_obj.unlink()
elif path_obj.is_dir():
shutil.rmtree(path)
else:
return (False, "Unknown path type")
return (True, "Deleted successfully")
except PermissionError:
return (False, "Permission denied")
except Exception as e:
return (False, f"Error: {str(e)}")
def main():
parser = argparse.ArgumentParser(
description='Interactive safe deletion'
)
parser.add_argument(
'paths',
nargs='*',
help='Paths to delete'
)
parser.add_argument(
'--batch',
metavar='FILE',
help='Read paths from file (one per line)'
)
args = parser.parse_args()
# Collect paths
paths = []
if args.batch:
# Read from file
batch_file = Path(args.batch)
if not batch_file.exists():
print(f"❌ Batch file not found: {args.batch}")
return 1
with batch_file.open('r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
paths.append(line)
else:
paths = args.paths
if not paths:
parser.print_help()
return 1
# Prepare items
items = []
for path in paths:
size = get_size(path)
description = get_description(path)
items.append((path, size, description))
# Remove non-existent paths
items = [(p, s, d) for p, s, d in items if Path(p).exists()]
if not items:
print("❌ No valid paths to delete")
return 1
# Interactive mode
if len(items) == 1:
# Single item - simple confirmation
path, size, description = items[0]
if not confirm_delete(path, size, description):
print("\n✅ Deletion cancelled")
return 0
success, message = delete_path(path)
if success:
print(f"\n{message}")
print(f" Freed: {format_size(size)}")
return 0
else:
print(f"\n{message}")
return 1
else:
# Multiple items - batch confirmation
selected = batch_confirm(items)
if not selected:
print("\n✅ Deletion cancelled")
return 0
# Delete selected items
print(f"\n🗑️ Deleting {len(selected)} items...")
print("" * 50)
success_count = 0
total_freed = 0
for path, size, description in selected:
success, message = delete_path(path)
status_icon = "" if success else ""
print(f"{status_icon} {path}: {message}")
if success:
success_count += 1
total_freed += size
print("" * 50)
print(f"\n📊 Results:")
print(f" Successfully deleted: {success_count}/{len(selected)}")
print(f" Total freed: {format_size(total_freed)}")
return 0 if success_count == len(selected) else 1
if __name__ == '__main__':
sys.exit(main())