Skip to content

Refresh Homebrew cache and improve app source handling - #44

Merged
iamr8 merged 8 commits into
mainfrom
develop
Aug 8, 2026
Merged

iamr8 merged 8 commits into
mainfrom
develop

Conversation

@iamr8

@iamr8 iamr8 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

No description provided.

iamr8 and others added 8 commits August 8, 2026 12:56
Formulae and casks were silently reported as up-to-date when Homebrew's
local API cache was stale. `brew info` (the only Homebrew command this
scanner runs) never triggers Homebrew's auto-update, so `versions.stable`
lagged the real latest between refreshes and outdated packages went
unlisted. Refresh the cache with `brew update --quiet` (metadata only —
never `upgrade`, installed packages untouched) when it is older than a
threshold before reading it.

Also reconcile an app discovered from two sources — a scanned .app bundle
and its Homebrew cask. They are separate update channels (e.g. a Sparkle
self-updater vs the cask) whose versions can legitimately differ, so both
surface: the scanned app stays the parent and the cask is attached as a
sub-app (one level deep). When the cask installs the same bundle the
on-disk version is authoritative — brew's receipt lags for casks that
auto-update themselves — so the sub-app reports the bundle's version and
is not falsely flagged outdated. Parents roll up sub-app updates so a
cask-channel update still shows in the default outdated-only view.

Details:
- Version-robust staleness check globs *.jws.json (handles the brew 6.x
  internal/packages layout) and honours HOMEBREW_CACHE; window is
  configurable via APPS_BREW_CACHE_MAX_AGE_HOURS (default 6h).
- Reusable cask/app matcher (artifact target path, *.app name, or bundle
  id; case-insensitive) drives same-bundle detection and cross-source
  de-duplication when display names differ.
- Correct a misleading "already updated to v{installed}" debug log.
- Bump VERSION to 0.0.13-beta.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A same-named app and extension — e.g. the "Claude" desktop app and the
"Claude" Chrome extension — were collapsed into one parent + sub-app entry
because ScanOrchestrator de-duplicated on name alone, nesting an
Application under an Extension and hiding the desktop app's own update
status. Key the cross-scanner de-duplication on name AND kind so they stay
distinct top-level entries and are each checked on their own; genuine
same-kind duplicates still merge into sub-apps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Some VS Code extensions ship an NLS placeholder such as `%displayName%`
as their package.json displayName (a key into package.nls.json the
manifest never inlines). The scanner used it verbatim, so several
extensions all showed up named "%displayName%" and collided. Reject the
placeholder so the extension id (e.g. github.vscode-pull-request-github)
is used as the name instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keying on name (and then name+kind) alone still merged same-named items
from different scanners — the "EditorConfig"/"PowerShell" JetBrains
plugins vs their VS Code extensions — nesting unrelated software. Include
the source scanner in the de-duplication key so only genuine duplicates
from the same scanner collapse. The manual-app + Homebrew-cask pairing is
unaffected: it is reconciled inside MacApplicationsScanner and reaches the
orchestrator as a single record.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apps whose update status could not be determined were shown dimmed with a
leading "?" on the name. Flag the row red instead — mirroring how outdated
rows are flagged green — by colouring the name and version red and
dropping the secondary dimming on the kind and source columns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The discovered total counted only top-level records while the checked
total also counts sub-apps (a scanned bundle's Homebrew cask channel is
checked on its own), so "Discovered 244 · Checked 246" looked
inconsistent. Include sub-apps in the discovered total so both cover the
same set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Log the nullable cache write time directly instead of a redundant
  null-conditional the analyzer flags as a constant condition.
- Map file write times with Select/Max instead of a manual foreach.
- Match cask artifact app entries with Any instead of a foreach filter.
- Use Path.Join (never drops earlier segments) instead of Path.Combine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@iamr8
iamr8 merged commit 5bc417e into main Aug 8, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant