- Parallelize project cache indicator checks and root scans in caches.sh
(sequential find per $HOME/* dir → throttled background jobs)
- Pre-compute project name cache before purge display loop, eliminating
O(N²) filesystem traversals in get_artifact_display_name
- Replace basename/dirname subshells with parameter expansion in
get_project_name/get_project_path hot loops; depth counter via
bash string arithmetic instead of echo|tr|wc|tr pipeline
- Eliminate mktemp/awk/rm per call in app_support_item_size_bytes,
use command substitution to capture du output directly
- Defer tr lowercase in clean_application_support_logs to only when
first 3 protection checks fail; replace basename with ${var##*/}
- Optimize trash item counting: find -print0|tr -dc '\0'|wc -c
avoids per-file fork from -exec printf
- Add -maxdepth 5 to /private/var/folders find (X dir is always at
depth 3, code_sign_clone at depth 5 max; verified on real machine)
- lib/clean/user.sh: quote glob patterns in _clean_incomplete_downloads so
they are not expanded at array assignment time; filenames with spaces would
previously be word-split before reaching safe_clean, causing silent failures
- lib/clean/project.sh: replace silent array fallback with explicit bounds
check before reading PURGE_CATEGORY_FULL_PATHS_ARRAY, guarding against
future index drift if menu filtering is added
- SECURITY_AUDIT.md: document double validatePath in analyze delete, native
PAM passthrough for sudo prompts, dry-run dedup by filesystem identity,
atomic purge config write, pre-commit hook mirroring CI, and new test suites
* removed duplicate calls to clean_xcode_tools and clean_code_editors
in lib/clean/app_caches.sh clean_user_gui_application() was making calls
to clean_xcode_tools and clean_code_editors.
in lib/clean/dev.sh clean_xcode_tools and clean_code_editors was also
being called, causing the duplication when executing the clean command.
removed the calls from lib/clean/app_caches.sh
clean_user_gui_application since these two calls are developer focused.
* test: cover removed developer app calls
---------
Co-authored-by: Tw93 <hitw93@gmail.com>
Add a lightweight top-level entry cap to Containers and Group
Containers scanning. When a cache directory exceeds the threshold,
skip the expensive per-item du/find size scan and take a partial-size
/ "cleaned" output path instead. Replace find-piped-to-read loops
with pure-bash glob iteration to cut external process overhead.
Closes#586
Add MOLE_TEST_MODE=1 checks to skip AppleScript osascript calls
and sudo operations that trigger system permission dialogs during tests:
- lib/check/all.sh: Skip login items listing
- lib/clean/apps.sh: Skip running app detection
- lib/clean/user.sh: Skip Finder trash operations and sudo test calls
- lib/core/log.sh: Skip sudo status check in debug log
- lib/uninstall/batch.sh: Skip login item removal
Also add MOLE_TEST_MODE=1 export to all test files that load
these modules to ensure consistent test isolation.
Before deleting .download/.crdownload/.part files, check lsof to
detect open file handles. Files held by an active browser process
are skipped with a warning instead of being deleted.
Fixes a case where a 12GB IPSW being downloaded in Safari was
removed mid-download because the .download bundle matched the glob.
Add hint_is_system_binary() to short-circuit detection for plists that
use /bin/*, /usr/bin/*, /usr/libexec/* etc. as their program path.
These are custom scripts, not app-backed launch agents, so the stale
detection logic does not apply. Previously the function relied on the
absence of AssociatedBundleIdentifiers as an implicit skip, which could
fail on certain macOS plutil edge cases.
Also add teardown() in clean_hints.bats to explicitly remove the
LaunchAgents directory after each test, and add run_with_timeout mock
in the "skips custom shell wrappers" test to prevent mdfind from
influencing results. This eliminates the intermittent failure where
test 70 showed "Review:" in output without "Potential stale login item:".
The path column in 'mo purge' selection was capped at 60 characters
regardless of terminal width. On wide terminals (120+ cols) this caused
long project paths like ~/GitHub/Ulama/transformer-project to be
truncated unnecessarily to ~17 visible characters.
Remove the hard 60-char cap and let the available terminal space be the
only upper bound, which is already computed as:
available_for_path = terminal_width - fixed_overhead
Paths now use as much space as the terminal allows while still keeping
the size and artifact-type columns readable.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sequential du calls with 15s timeout each meant N artifacts × 15s of potential
wait when paths are on slow storage (network mounts, Syncthing, large dirs).
Now all du processes are launched concurrently; total time is bounded by the
single longest call (≤ 15s) rather than N × 15s.
fix(protection): protect CoreAudio paths in should_protect_path (issue #553)
Add com.apple.coreaudio*, com.apple.audio.*, and coreaudiod* to the protected
path patterns so deep-clean cannot touch audio subsystem caches, reducing risk
of audio output loss on Intel Macs running macOS Sequoia.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When no artifacts are found during scanning, `menu_options` remains an
empty array. With `set -euo pipefail` active, expanding `${menu_options[@]}`
on an empty array causes a fatal "unbound variable" error (line 1325).
Add an early-return guard after the spinner stops: if no items were found,
print a friendly "No artifacts found to purge" message and exit cleanly.
Fixes#546
- Use array slicing instead of manual loop for splitting dirs
- Remove redundant early returns with duplicated safe_clean calls
- Consolidate cache/logs cleanup to single location at function end
- Fix undefined ICON_SKIP, use ICON_SUCCESS instead
- Reduce code from 46 to 27 lines with early return pattern
- Consistent styling with other whitelist skip messages
- Add whitelist checking to clean_dev_go() function
- Check both GOCACHE and GOMODCACHE before cleaning
- Show appropriate messages for protected caches
- Fix whitelist pattern from ~/go/pkg/mod/cache/* to ~/go/pkg/mod/*
- Split Go cache into separate build and module entries
Fixes#521
- Add simctl availability check before attempting cleanup
- Capture and analyze error output for better diagnostics
- Implement fallback: manual deletion when simctl fails
- Provide specific error hints (permission, in-use, service issues)
- Skip early when no unavailable simulators exist
- Show partial success status when some deletions fail
Error scenarios now handled:
- simctl not available → skip with friendly message
- Permission denied → show hint and try manual deletion
- Device in use → show hint and try manual deletion
- CoreSimulator service issues → show hint
- Partial failures → show "partially cleaned X/Y"
Fixes#520
On macOS 15+, /usr/bin/pip3 exists as a stub that triggers Command Line
Tools installation dialog. The previous check only verified command
existence, causing false "pip cache · would clean" output for users
without actual pip3 installed.
Now verifies pip3 is functional by checking `pip3 --version` before
attempting cleanup.
Fixes#512
Use a fast `defaults read` pre-check before spawning any tmutil
process. On machines without Time Machine configured the check
returns instantly, avoiding the spinner and the 2-3s tmutil timeout.
Affected locations:
- lib/clean/system.sh: clean_time_machine_failed_backups()
- lib/clean/system.sh: clean_local_snapshots()
- lib/clean/user.sh: local snapshot hint in system hints