Replace glob pattern with find command to properly clean dotfiles
in Trash when osascript fallback is used. The old pattern
~/.Trash/* does not match files starting with "." in bash.
This fix ensures that hidden files like .DS_Store, .hidden_file,
etc. are properly removed when cleaning the Trash.
Issue #393 reported mo clean hanging on 'Scanning sandboxed apps'
and 'Scanning orphaned app resources'.
Root cause: should_protect_data() was looping through 332 patterns
(28 SYSTEM_CRITICAL_BUNDLES_FAST + 304 DATA_PROTECTED_BUNDLES).
For 662 sandboxed containers, this resulted in 220,000+ pattern matches.
Solution: Replace loops with fast case statement for common prefixes:
- com.apple.* (system apps) - instant return
- com.microsoft.*, com.jetbrains.* (IDEs) - instant return
- Password managers, VPNs, Docker etc. - instant return
- Other apps - instant return (no protection needed)
- Only check detailed list for special wildcards (com.tencent.* etc.)
Performance: Clean command maintains 35s (same as previous optimization)
Functionality: All 9 protection tests pass
Fixes text remnants and extra blank lines when spinner messages change.
Issues fixed:
1. Text remnants when switching from longer to shorter messages (e.g., 'Cleaning...ems...')
2. Extra blank lines appearing after section headers
Root causes:
- \033[K only clears from cursor to end of line, leaving remnants when new messages are shorter
- stop_section_spinner was clearing lines even when no spinner was running
Changes:
- lib/core/base.sh:
- Changed stop_section_spinner(), safe_clear_line(), safe_clear_lines() to use \033[2K
- Added guard in stop_section_spinner to only clear when spinner is actually running
- lib/core/ui.sh:
- Clear line once when starting spinner (before loop) to ensure clean start
- Normal spinner rotation uses \r without clearing (performance optimization)
Performance: Line clearing happens only once per spinner start, not on every loop iteration.
Fixes#390
- Replace time.After() with reusable timer to reduce GC pressure
- Use pre-compiled regex for app bundle matching (O(1) vs O(N))
- Fix Bash 3.2 compatibility (remove local -n usage)
- Add get_timestamp() helper and optimize log rotation
- Create mo log viewer with search/filter capabilities
- Improve test coverage to 18.4% with better assertions
- Add security fixes for grep injection prevention
- Validate bundle_id format (reverse-DNS) in stop_launch_services() to prevent glob injection attacks
- Add common word exclusion list for LaunchAgents name search to avoid false positive matches (Music, Notes, Photos, etc.) - Add security comments explaining symlink handling in remove_file_list()
- Improve brew_uninstall_cask() timeout handling: exit code 124 now returns failure immediately
- Update SECURITY_AUDIT.md with remediation details
- Change Rosetta 2 status from warning to info
- Remove auto-fix suggestion for missing Rosetta 2
- Update tests to reflect new behavior (3 -> 2 expected fixes)
- Replace parentheses with commas for supplementary info
- Use commas instead of em-dashes for separators
- Update bullet points from - to * in some contexts
- Improve version extraction regex with fallback logic
- Refactor JetBrains Toolbox cleanup with _restore_whitelist helper
- Add MOLE_EDGE_APP_PATHS env var for test isolation
- Fix Edge old versions tests to avoid scanning system Edge installation
Add checks for empty product_dirs and version_dirs arrays before
iterating to prevent "unbound variable" errors when running with
set -u (pipefail) and the JetBrains Toolbox directory doesn't exist
or contains no products.
- Empty trash using macOS Finder API (osascript) for proper permission handling
- Respects whitelist protection (skips if Trash is whitelisted)
- Shows item count when emptying trash
- Fallback to direct cleanup if Finder API fails
- Supports dry-run mode
Issue: #362
- Add fallback to mo --version when brew list fails
- Add error handling for debug log write failures
- Improve version extraction with multiple fallback strategies
- Export MOLE_DRY_RUN env var for subprocess visibility
- Add || true to grep commands to prevent pipeline failures
- Add dry-run test for clean_orphaned_system_services
- Simplify clean_local_snapshots tests
- Replace 48-line custom function with one-line safe_clean call
- Remove unnecessary interactive confirmation (consistent with other browser caches)
- Simplify tests to verify Puppeteer cache is in clean_browsers output
- Net: -93 lines of code for same functionality