Skip to content

Releases: trsdn/OpenSwitchr

Release list

v0.2.1

Choose a tag to compare

@trsdn trsdn released this 19 Sep 16:46
9731019

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

Choose a tag to compare

@trsdn trsdn released this 19 Sep 16:36
6a35cf1

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 in docs/self-assessment.md and 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.plist is checked against the newest release heading in this file, and
    the minimum macOS version is checked across Package.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 as Info.plist keys, plus the licence text
    copied into Contents/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 CODEOWNERS file, a Dependabot
    configuration for the pinned action versions, .github/github-app.yml, and a
    markdown lint workflow.
  • .gitattributes, marking Resources/AppIcon.icns as 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
    UserDefaults under com.openswitchr.app and how to read or delete them,
    the project is English-only, and which accessibility limitations are known.
  • AGENTS.md now 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 on WindowInfo.isFullScreen so the event tap never has to ask.
    openswitchr-diag --filters reports 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 calls ThumbnailProvider.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 with openswitchr-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 is TileSizing, 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

  • main is 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.md was 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 in trsdn/.github — the reusable conformance
    workflow resolves the standard at its published tag, and the untagged
    1.12.0 bump on its main is 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@v4 and the reusable conformance workflow
    pinned to @main can both change underneath the repository.
    docs/self-assessment.md and the badge are updated to match.
  • The rule deciding whether a CoreGraphics window with no accessibility
    counterpart belongs in the index moved out of WindowIndex.apply into
    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 pinned exact: with
    Package.resolved committed, 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.txt carries AppUpdater's (Unlicense) and its dependency
    Version's (Apache-2.0) licenses verbatim and is copied into the bundle. The
    broker side (an OpenSwitchr-<semver>.dmg asset, 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 in RELEASE_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.xcstrings for the app and UI.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. LocalizationCatalogTests fails 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's openswitchr adapter now copies the .lproj
    directories too (trsdn/mac...
Read more