Releases: trsdn/OpenSwitchr
Releases · trsdn/OpenSwitchr
Release list
v0.2.1
Fixed
- The German localization is now actually in the release. 0.2.0 was built by a toolchain that copied the string catalogs instead of compiling them, so it shipped English only; the release build now compiles them itself and refuses to ship without German.
v0.2.0
Added
- Repository conformance record at
.github/conformance.yml, assessed against
version 1.5.1 of the trsdn Repository Quality Standard, with the reasoning
behind every result indocs/self-assessment.mdand the badge rendered from
the record into.github/badges/conformance.svg. A scheduled workflow
re-validates both, so a record that drifts from its badge, or an assessment
that ages past the review cadence, turns the check red on its own. scripts/check.sh, the single command that validates a change before it is
proposed: build with warnings as errors, tests, markdown lint, and the bundle
metadata checks below. It needs no signing identity, no permissions, and no
network, so it behaves the same on a laptop, in CI, and for an agent.- Drift guards for the three facts nothing used to compare. The version in
Info.plistis checked against the newest release heading in this file, and
the minimum macOS version is checked acrossPackage.swift,
scripts/build-app.sh, and the README badge. All of them had been maintained
by hand in parallel. - Product identity in the bundle: repository URL, issue tracker URL, licence
identifier, and copyright holder asInfo.plistkeys, plus the licence text
copied intoContents/Resources. The About tab now reads its links back out
of the bundle rather than hardcoding them a second time, so the shipped
metadata and what the user sees cannot disagree. - Issue forms for bug reports and proposals, a
CODEOWNERSfile, a Dependabot
configuration for the pinned action versions,.github/github-app.yml, and a
markdown lint workflow. .gitattributes, markingResources/AppIcon.icnsas generated. It is
rewritten by every build, so hand-editing it accomplishes nothing.- README sections stating the cases that were previously only implicit: the app
collects nothing and opens no outbound connection, preferences live in
UserDefaultsundercom.openswitchr.appand how to read or delete them,
the project is English-only, and which accessibility limitations are known. AGENTS.mdnow names the operations an agent must not perform, the paths that
are generated, and the review expectation for agent-authored changes.WindowFilter: one pure value type describing which windows a surface wants
and in what order, applied by both frontends. Four axes — application scope,
minimized handling, display scope, and order — with the switcher's
configurable in Settings and the Dock preview's fixed and permissive, because
the pointer already chose the application. Defaults reproduce the previous
behaviour exactly.openswitchr-diag --filters, which applies the profiles to the windows
actually open and checks the one axis unit tests cannot judge: that scoping
by display leaves no window claimed by no display.- Dock previews can switch instantly while one is already open, so the open
delay applies to the first preview only and moving along the Dock does not
wait again. On by default. A hover that resolves before the index has caught
up is retried once the rebuild lands, rather than leaving the pointer on an
icon with nothing shown. - A per-application rule table (
AppRule,AppRuleTable), keyed by
bundle-identifier prefix, with two independent axes: hide a window outright
(never / always / when its title matches), and stand aside for it — swallow
nothing, raise nothing — while it is frontmost and full screen. Ships with
verified defaults for the known correctness case: a remote desktop, screen
share, or virtual machine running full screen now gets the switcher hotkey
itself rather than an overlay raised over it. Full screen is detected once
per rebuild, from the window's frame against the display it covers, and
carried onWindowInfo.isFullScreenso the event tap never has to ask.
openswitchr-diag --filtersreports both against the windows actually open. - A minimized window keeps its last good thumbnail. ScreenCaptureKit cannot
capture a window in the Dock, so that image is the only preview there will
be; the store now exempts it from the refresh age limit (which it could never
satisfy), evicts it after every live entry when the byte budget is exceeded,
and drops it when the window is restored so the first frame after restoring
is not stale. The tile already dims a minimized preview and marks it as such. - Icon-and-title tile mode, chosen deliberately instead of by accident. A
"Tiles show" setting picks previews or icons only, and previews switch to
icons on their own when Screen Recording is not granted (every capture would
fail) or when a surface has more than twelve windows (each preview too small
to identify). The threshold is a named constant per surface. In icon mode
nothing callsThumbnailProvider.prefetch, so a busy Space costs zero
captures; the mode is decided when a panel opens and kept for that session,
and the cache is left valid rather than cleared. For scale, eight cold
parallel captures measured ~340 ms withopenswitchr-diag --bench --capture. - Switcher tiles can shrink so every window fits without scrolling
("Shrink switcher tiles so every window fits", on by default). The configured
width is the upper limit and is never exceeded: with a few windows nothing
changes, and with more than fit in the overlay's three visible rows the tile
steps down in twenty point steps until they do. Sizes are quantised so the
thumbnail cache keeps hitting and the step is what is captured, and below the
legible floor the switcher uses icon tiles instead of a smaller image. The
layout maths isTileSizing, pure and unit tested. - Thumbnail captures are bounded, prioritised, and cancellable
(CaptureLimiter, unit tested). At most four run at once instead of one per
tile, the selected tile is asked for first and jumps the queue, and dismissing
a panel cancels every capture that has not started, so they do not complete
into a cache nobody will read. A cancelled request records nothing, so a later
one simply tries again.
Changed
mainis protected: pull requests are required, the three CI checks must
pass, and force pushes and branch deletion are blocked. Secret scanning, push
protection, Dependabot security updates, and private vulnerability reporting
are enabled.- The repository quality section of
AGENTS.mdwas reassessed. It had described
a default branch holding two files, which stopped being true when the work was
merged, and it assessed against version 1.3.3 of a standard now at 1.5.1. - Reassessed against version 1.11.1 of the standard (previously 1.5.1), the
latest version actually tagged intrsdn/.github— the reusable conformance
workflow resolves the standard at its published tag, and the untagged
1.12.0 bump on itsmainis not yet consumable. No criterion regressed; the
ten added since 1.5.1 were assessed for the first time and surfaced one real
gap,S12:actions/checkout@v4and the reusable conformance workflow
pinned to@maincan both change underneath the repository.
docs/self-assessment.mdand the badge are updated to match. - The rule deciding whether a CoreGraphics window with no accessibility
counterpart belongs in the index moved out ofWindowIndex.applyinto
WindowAdmission.admits, where it is documented and unit tested. Behaviour
is unchanged.
Fixed
- In-app updates from GitHub Releases (#30), through
AppUpdater 4.1.2 pinnedexact:with
Package.resolvedcommitted, the same setup as the sibling apps. This is the
app's first third-party dependency and its first network connection, so the
README's Privacy section, the project page and Settings now say so: one daily
request to GitHub, no identifier, and "Check for Updates Automatically" turns
it off entirely. The menu gains Check for Updates…, an update that is ready
offers "Install and Restart", and the app stops its event tap, Dock observer and
panels before the bundle is replaced. The schedule (UpdateSchedule: a daily
check that wakes hourly so a slept-through deadline catches up, and survives a
clock that moved back) and the state rules (UpdateState: a failed background
check stays silent, a manual one always answers) are pure and unit tested.
THIRD_PARTY_NOTICES.txtcarries AppUpdater's (Unlicense) and its dependency
Version's (Apache-2.0) licenses verbatim and is copied into the bundle. The
broker side (anOpenSwitchr-<semver>.dmgasset, the dependency lock, the
resource bundle) landed in trsdn/macos-notarization-broker#56, but no release
with the updater has been built, and a real update has never been run, both
recorded inRELEASE_CHECKLIST.md. - Two German layout and wording fixes found by rendering the Settings views
offscreen in German for the first time (#57): the "Präfix der Bundle-Kennung"
label wrapped onto two lines and squeezed its own text field, so it is now the
field's prompt; and the update explanation switched to informal "du" while every
other string is impersonal. The other tabs, including the two labels #5 warned
about, fit without truncation. - The interface is localized, with German as the first additional language
(#5). Two String Catalogs,Localizable.xcstringsfor the app andUI.xcstrings
for the shared views, are compiled by SwiftPM and copied into the app bundle by
scripts/build-app.sh; counts use plural variants; the product name and the
modifier symbols are never translated.LocalizationCatalogTestsfails on an
untranslated entry, a dropped placeholder, an incomplete plural, a lost product
name, or a plain literal that never reached a catalog (mutation-tested). The
German was written by an AI assistant and has not been reviewed by a native
speaker. The release broker'sopenswitchradapter now copies the.lproj
directories too (trsdn/mac...