Releases: ltdan-88/brew-launcher
Release list
v0.85.1
Fixed
- Every "here's how to get tmux" message (
--diagnose, F1 help, the F9
Launch Preset and Create Preset fallbacks) hardcodedbrew install tmux, even on the pacman backend where that command doesn't work.
Found while packaging the pacman backend for the AUR. Now says
sudo pacman -S tmuxon that backend, unchanged on Homebrew.
brew install ltdan-88/brew-launcher/brew-launcherv0.85.0
Added
- A real, working pacman backend for Arch Linux, alongside Homebrew —
the launcher now works without Homebrew installed at all.
BREW_LAUNCHER_BACKEND(auto/homebrew/pacman) picks which
package manager it talks to;auto— the default — prefers Homebrew
whenever it's onPATHand only falls back to pacman when it
genuinely isn't, so this changes nothing for any existing Homebrew
user. Every screen — search, marking, categories, favorites,
presets, themes, the details pane — works identically either way;
only where the tool list itself comes from differs. Update and
Update All decline with a plain explanation on the pacman backend
rather than attemptingpacman -S/-Syu, since those need root and
this script isn't going to ask for that on its own. Not yet packaged
for Arch (no AUR entry) — for now this means cloning the repo and
runningbin/brew-launcherdirectly. See the README's
"Other package managers" section (tucked inside Configuration —
nothing to read here if you're on Homebrew).
brew install ltdan-88/brew-launcher/brew-launcherv0.84.0
Changed
- Launch Flags now offers the same F3/⌥D on-demand
--helppreview
Run With Args already had, and Run With Args' own footer now says
so too. Raised live: two separate remarks about the same
inconsistency — Run With Args' F3 preview was only mentioned in its
header text, not its footer (the one thing actually visible without
reading the rest of the screen), and Launch Flags didn't offer the
preview at all despite being Run With Args' closest sibling. Both
screens now wire up--internal-preview-usageand bind F3/⌥D to
toggle-previewidentically, and both footers sayF3/⌥D [Preview].
brew install ltdan-88/brew-launcher/brew-launcherv0.83.0
Added
- Esc clears a marked set, ahead of stepping back a view or quitting.
Raised live: "do we have a keybind to unselect all?" — after Ctrl-A
(toggle-all) turned out to invert a mixed marked set row-by-row rather
than cleanly clearing it (confirmed live), there was no key that reliably
gave up on a batch. Folded into Esc rather than a new bind, as its own
priority step: closes the details pane first if it's open as a peek
(unchanged), then clears a marked set if anything's marked (new), then
steps back a view or asks to quit (unchanged). Detecting "anything
marked" needed fzf's own$FZF_SELECT_COUNT, which only exists inside
the fzf process itself — a newMARKED_COUNT_FILEside-channel (same
pattern as the existing footer/header click files) carries it out, written
by the same marking binds that already update the live footer.
brew install ltdan-88/brew-launcher/brew-launcherv0.82.0
Added
- Ctrl-A marks (or unmarks) every row the current search matches.
Raised live: "are there any improvements we can still make to make
navigation and usability even easier?" Marking used to be one row (or
one click) at a time — narrowing down with a search or a category first,
then acting on the whole result, had no way to select all of it short of
Tab-ing through each row. Bound to fzf's owntoggle-all, confirmed live
before relying on either property it depends on: filter-aware (only
marks what the current search actually matches, not literally every row
ever loaded) and a real toggle (pressing it again on a fully-marked
batch clears it, not a one-way select-all). Same live footer feedback
Tab/Shift-Tab/right-click already get. Main list only — Create Preset's
own marking screen tracks launch order, which fzf's native multi-select
has no concept of, so it wasn't a drop-in fit there.
brew install ltdan-88/brew-launcher/brew-launcherv0.81.0
Added
- A new "Uncategorized" view in F2 — raised live: "I'd like to have a
category called 'Uncategorized'." Computed, not a real category file
(same family as All/Hidden/Most Used/Recently Launched/Recently Added):
every installed, non-hidden command that isn't filed anywhere — no
category you made, no bundled default either.
Being favorited alone doesn't count as filed, matching how the#
marker already treats it. F3 previews its contents like every other
row now does; Ctrl-R/Ctrl-D refuse it the same way they refuse every
other built-in view.
Fixed
load_bundled_categories()misreading a cache row with an empty
description or size, the same class of bug just fixed in
load_bundled_hidden_commands()(v0.79.0) — found while building the
above, since it's exactly the function the new Uncategorized view
depends on for correctness. Two placeholders sat after the category
field in the old zshreadloop, so a collapsed empty field didn't
just come back empty the way it did there — it shifteddefault_hidden's
own value ("0" or "1") into what the code thought was the category
name, meaning a formula could have silently been "filed" into a bogus
category literally named "0" or "1" instead of its real one. Fixed the
same way:awkinstead of areadloop with placeholder variables.
brew install ltdan-88/brew-launcher/brew-launcherv0.80.0
What
Details (turned on via Actions → Settings → Details) now survives a
relaunch, not just the current session.
Why
Raised live: "changing themes and relaunching toggles the details
pane into off in settings."
Picking a theme relaunches the whole process to apply the new colors
(pick_theme()'s own exec). DETAILS_VISIBLE/DETAILS_PINNED had
never been written to config at all — a deliberate "per-session view
preference, not a setting" choice from when this first shipped, which
made Details the one row in Settings that didn't actually behave like
a setting (everything else there — Theme, Startup Screen, Sort,
Compact View, Details Position, Alt Keybinds — already persists).
This is the third distinct report rooted in the same gap: the earlier
"not always persistent" fix already closed it for a stray F3 press
within one session; this is that same gap reached through a different
door (any real process restart, not only F3). Fixed it properly this
time instead of special-casing the theme-relaunch trigger.
Implementation
A new DETAILS= config key, read at startup the same way every other
setting already is, written only from open_settings_menu()'s
toggle_details case. F3 itself still never writes it — a peek stays
a peek, and stays a no-op while Details is pinned on regardless of
whether that pin came from this session's own Settings press or a
config file read at startup.
Verification
- Confirmed live in tmux, not just checked the file: turned Details
on via Settings, killed the session and started a fresh one against
the same$HOME, confirmed it was already pinned on with no keys
pressed — then turned it back off and confirmed a second relaunch
stayed off too. test/details-pinned-f3-fixtures.shextended with source-text
checks (config parsing, startup seeding, the write site, F3 never
writing) and the two live relaunch checks.- Proved the test catches the regression two ways (write removed;
startup-seeding text kept but effect defeated) before restoring. - Full local suite passes.
- README,
EXTENDING.md, F1's Details topic updated.
🤖 Generated with Claude Code
v0.79.0
What
Fixes load_bundled_hidden_commands() silently failing to register a
bundled-hidden command whenever an earlier cache field (description or
size) is genuinely empty.
Why
Found while live-verifying the previous PR (F2's F3 preview for
computed views): an All count on the view picker that disagreed with
what F3 actually listed for the same view.
load_bundled_hidden_commands() read the cache with a zsh read loop
and placeholder variables for the fields between the command name and
default_hidden (field 11). IFS=$'\t' read treats a run of
consecutive tabs the same way it treats a run of ordinary whitespace —
as a single separator — so a genuinely empty field doesn't consume a
placeholder of its own, and the read ends up one token short by the
last variable, regardless of what field 11 actually held.
Two fields a real formula's cache row can actually come back empty for
(unlike default_category, field 10, which was already given a
non-empty "-" placeholder specifically to dodge this exact bug class
— see cache_writer.py's own comment): description (no desc from
brew info) and size (no entry in brew info --sizes).
Fix
Read field 11 with awk instead — the same technique
--internal-preview-category's own equivalent lookup already uses for
the same field.
Verification
- Reproduced the wrong result with a hand-built cache row before
touching any code, confirmed the fix corrects it. - Confirmed live in a real tmux session: a bundled-hidden entry with
an empty description madeAllovercount before the fix, correctly
excluded it after. test/ignore-fixtures.shextended with both realistic empty-field
cases. Proved it catches the regression by reverting to the old
read-based version and confirming failure, then restored.- Full local suite passes.
🤖 Generated with Claude Code
v0.78.0
What
F2's F3 preview now lists real content for All, Hidden, Most Used, Recently Launched, and Recently Added, instead of "Not a
stored category — nothing to preview."
Why
Raised live: "why wouldn't it list the TUIs regardless of whether it
was a stored category?" These five aren't backed by a
CATEGORIES_DIR file — that's still true, and is exactly why they
were skipped in the first place — but that's a reason the preview
code hadn't been built for them, not a reason they can't be
previewed. Each is computable from data the preview can already
reach: the cache itself (All/Hidden), and the plain launch-history log
plus the cache's own install-time field (Most Used/Recently Launched/
Recently Added).
Implementation
- All/Hidden: same hidden/shown/bundled-hidden combining rule the
real-category branch already uses, read straight from the cache. - Most Used/Recently Launched/Recently Added: numbered by rank
(not alphabetical — sorting away a ranked view's whole point would
defeat the preview), capped at the sameCOMPUTED_VIEW_LIMIT(15)
the real view enforces. A launch-history entry for a since-
uninstalled command is excluded, same as the real view only ever
shows entries that still exist in the cache. - Confirmed tie-break direction against the real, shipped
build_entries()directly rather than assumed —${(On)array}
sorts ascending then reverses the whole array, so ties land reverse-
alphabetical, not forward. Matched that exactly rather than
"fixing" it to something more intuitive but inconsistent with the
real view.
Verification
test/picker-details-fixtures.shextended with a dedicated,
save-and-restore cache/launch-history fixture covering all five
views, hidden-exclusion, the stale-launch-history case, the Empty
case, and the 15-tool cap (with a genuine tie, to prove where it
actually lands).- Proved two different regressions fail this test (the whole new
branch removed; just the stale-history exclusion removed) before
restoring. - Verified live in tmux: seeded cache + launch history, opened F2,
confirmed All/Most Used render real content. - Full local suite passes.
- README,
--help, F1's Keys topic updated.
🤖 Generated with Claude Code
v0.77.0
What
F3 drops out of the footer entirely while Details is pinned on via
Settings (both the main list and F2's view picker), and reappears the
moment it's turned back off.
Why
Direct follow-up to the previous PR, raised live: "why don't we hide
F3 in the bottom menu, when it is basically unusable?"
Pushed back on the framing first — F3 is only inert in the one
narrow, self-chosen state (Details pinned via Settings), not in
general — and pointed at an existing precedent that argues against
hiding footer items on principle: F9/Presets stays visible even
without tmux specifically because an earlier version hid it, and that
meant nobody without tmux ever discovered Presets existed at all.
Asked how to proceed given that tension; the answer was a general
principle — "hide menus in general that are not usable" — applied
here to the specific case under discussion.
Implementation
Both footer call sites that carry an F3 entry now build it
conditionally on DETAILS_PINNED:
footer_actions()(main list) — conditional append.pick_view()'s (F2)view_footer_specs— built as an array, F3
only added when unpinned.
Deliberately not extended to F9/Presets-without-tmux or any other
"sometimes unusable" item — that would override a different, already-
reasoned decision well outside what was asked about here.
Verification
- Both call sites checked as source text.
test/details-pinned-f3-fixtures.shextended: live tmux run
confirms F3 is present with Details off, gone from both footers the
instant it's pinned on (every other entry still shown), and back
once unpinned (with the pane closing too).- Proved the test catches the regression two ways per call site
(guard absent; guard present but defeated by an unconditional
append right after) before restoring. - Full local suite passes.
- README,
--help, F1's Settings Reference topic updated.
🤖 Generated with Claude Code