v0.4.4
Recommended install: brew install itsdezen/tap/tili —
Homebrew downloads via curl, which doesn't set macOS's
quarantine flag, so Gatekeeper never enters the picture.
The tarballs below are codesigned with tili's self-signed
certificate (hardened runtime) — see
CONTRIBUTING.md.
That's for a stable signing identity across releases (so
your Accessibility grant survives an upgrade), not for
passing Gatekeeper — a self-signed cert isn't notarized. If
you download tili.app directly from this page instead of
using Homebrew, Gatekeeper will still prompt on first launch:
right-click → Open, or xattr -d com.apple.quarantine tili.app.
Fixed
tili uninstallcould print a spuriousUnload failed: 5: Input/output errorfromlaunchctlbefore its own "uninstalled"
message.stop_daemoncalledlaunchctl unloadon a LaunchAgent
plist whenever the file existed on disk, even if launchd no longer had
that job loaded (e.g. the daemon had already unloaded itself via
stop_self). Now skips the unload when the job isn't actually loaded,
still removing the stale plist file either way.- A fresh install's first
tili startcould show notiliitem to
toggle in System Settings' Accessibility list. Right after
triggering the Accessibility prompt,tili-daemonrantccutil reset
on its own TCC entry — since the prompt's row is created
asynchronously by macOS, this reset raced it and deleted the row
before it was ever visible to toggle, on every single attempt. That
reset is gone. tili statuscould report the daemon "running" while hotkeys
silently didn't work. Input Monitoring was treated as a soft
condition — the daemon kept running in a degraded state if it wasn't
granted. It's now a hard gate like Accessibility: if Input Monitoring
isn't granted, the daemon stops itself and requires an explicittili startonce both permissions are granted, instead of half-running.brew install/brew upgradecould skip restarting the menu bar
badge (or the daemon) after an asymmetric LaunchAgent state.
post_install's restart gate checked onlycom.tili.daemon.plist's
existence before restarting both processes; each LaunchAgent is now
checked independently.
Full changelog: CHANGELOG.md