SIGN IN SIGN UP
tw93 / Mole UNCLAIMED

🐹 Deep clean and optimize your Mac.

0 0 123 Shell

fix(clean): resolve bundle IDs via filesystem when Spotlight misses (closes #732, closes #733) (#735)

* fix(clean): resolve bundle IDs via filesystem when Spotlight misses (closes #732, closes #733)

`mo clean` flagged two classes of false positives:

  - Potential stale login item: org.keepassxc.KeePassXC (issue #732)
  - Orphaned service: /Library/PrivilegedHelperTools/com.adobe.ARMDC.* (issue #733)

Both call sites relied exclusively on
`mdfind "kMDItemCFBundleIdentifier == '<id>'"` to decide whether the
app that owns a plist/helper is installed. Spotlight is unreliable for
this: indexing is sometimes disabled on /Applications, Homebrew casks
occasionally skip metadata importers, and Spotlight does not index
privileged helpers that live embedded inside a parent .app under
`Contents/Library/LaunchServices/<id>` (the SMJobBless convention used
by Adobe, 1Password, Docker, etc.).

Introduce `bundle_has_installed_app` in a new
`lib/core/bundle_resolver.sh` module. It keeps mdfind as the fast path
and, on a miss, walks `/Applications`, `/Applications/Setapp`,
`/Applications/Utilities`, and `~/Applications`, reading each
`Info.plist` for `CFBundleIdentifier` and checking each app's
`Contents/Library/LaunchServices` directory for a registered helper
with the given ID. Results are cached in parallel indexed arrays for
the session (macOS bash 3.2 has no associative arrays).

  - `hint_launch_agent_bundle_exists` now delegates to the resolver, so
    homebrew-installed apps like KeePassXC resolve correctly.
  - The generic fallback in `clean_orphaned_system_services` for
    PrivilegedHelperTools uses the resolver, so helpers shipped inside a
    parent .app (Adobe ARMDC, Acrobat CC Installer, etc.) are no longer
    flagged when the parent app is installed.

Tests cover: app-bundle-ID lookup on a Spotlight miss, SMJobBless
helper lookup inside a parent app, negative lookup for a ghost bundle
ID, rejection of malformed IDs, and cache honouring within a session.

* refactor(core): drop session cache from bundle_resolver

The cache was premature optimization: in practice the resolver is
called a handful of times per \`mo clean\` run, and the slow path is
gated by a 2s mdfind timeout plus a bounded \`find -maxdepth 1\` over
four app roots. Removing the parallel-array cache, its get/put
helpers, and the reset-for-tests function drops the module from ~118
lines to ~70 and removes an implementation detail from the public
surface (no more \`mole_bundle_resolver_reset_cache\`).

No behavior change for callers. The resolver still does Spotlight →
filesystem fallback, still rejects malformed IDs, still handles both
app-owned bundles (#732) and SMJobBless helpers embedded in a parent
.app (#733).

Tests:
- Removed the caching-specific test (validated implementation, not
  behavior).
- Kept the four functional tests covering Spotlight miss, SMJobBless
  helper discovery, negative result, and malformed-ID rejection.
S
Sebastian Breguel committed
6a055de434b1d9e6cb93ebf5284ad22c8b65dbbb
Parent: 3f94133
Committed by GitHub <noreply@github.com> on 4/14/2026, 7:22:32 AM