Skip to content

chore: release v0.8.18 - #2007

Merged
AprilNEA merged 2 commits into
masterfrom
release-plz/2026-10-23T11-41-03Z
Oct 25, 2026
Merged

AprilNEA merged 2 commits into
masterfrom
release-plz/2026-10-23T11-41-03Z

Conversation

@aprilnea

@aprilnea aprilnea Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

[0.8.18] - 2026-10-25

Added

  • (assets) ask the jsDelivr data API for the newest asset release (#2040)
  • (desktop) add a keyboard backlight duration timer (#1879)
  • (core,agent,gui) add guarded disable-keys controls (#993)
  • (core,agent,gui) add a press force setting for the MX Master 4 Haptic Sense Panel (#2021)
  • (hidpp) add capability-bound force sensing buttons (#2016)
  • (release) cut betas from a workflow and tell the tap about them (#2005)
  • (release) build a beta at its own version (#2004)
  • (xtask,ci) compose update channel files from per-release records (#2000)
  • (agent) drive the mock agent from a stdin control console (#2003)

Fixed

  • (assets) follow the 0.1 asset release line instead of pinning 0.1.0 (#2039)
  • (i18n) translate the receiver chooser, old-pairing cleanup, and update channel in Czech (#2034)
  • (cli) route backlight operations through the agent (#2031)
  • (windows) post the layout's scan code with keys a layout can move (#2028)
  • (overlay) draw the Windows Actions Ring without a window frame (#1913)
  • (agent) re-apply volatile settings after replacing a dead channel (#1997)
  • (i18n) translate the disable-keys strings in 22 locales (#2024)
  • (deps) update Tokio for AsyncFd soundness advisory (#2019)
  • (device) bound Bolt receiver identity reads (#2009)
  • (release) name Sparkle deltas so Sparkle applies them (#2002)

@greptile-apps

greptile-apps Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Low impact] This release preparation appears safe to merge.

Summary

Prepares release 0.8.18.

  • OpenLogi's package metadata and changelog now identify release 0.8.18.

Reviews (19) · Last reviewed commit: "chore(release): write whole-repo changel..." · Reviewed by Greptile

AprilNEA

This comment was marked as outdated.

@davidbudnick davidbudnick added dependencies Pull requests that update a dependency file platform: all Cross-platform issue type: build Build, dependency, or local compilation issue labels Oct 23, 2026
@aprilnea
aprilnea Bot force-pushed the release-plz/2026-10-23T11-41-03Z branch 16 times, most recently from 729f546 to aa2fceb Compare October 25, 2026 16:21
@aprilnea
aprilnea Bot force-pushed the release-plz/2026-10-23T11-41-03Z branch from 36cbc84 to 8b2a0f9 Compare October 25, 2026 20:09
@AprilNEA
AprilNEA merged commit d9fd33a into master Oct 25, 2026
25 checks passed
@AprilNEA
AprilNEA deleted the release-plz/2026-10-23T11-41-03Z branch October 25, 2026 20:11
JayHome137 added a commit to JayHome137/OpenLogi that referenced this pull request Oct 26, 2026
* ci(release): drop the Codex release-notes job and use GitHub's generated notes (AprilNEA#1999)

Codex never wrote the notes of a release; every run fell back to GitHub's
generated list. Publish now asks GitHub for that list directly with
`gh api .../releases/generate-notes` and `github.token`, passing the
`previous_tag` the version job prints. A failed call leaves a compare
link and a warning, so the notes still never block a release.

Remove the Node tool under .github/scripts/release-notes, its pnpm
install in .agents/setup, the ast-grep rule that only matched its
TypeScript, and the docs that described it.

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(release): name Sparkle deltas so Sparkle applies them (AprilNEA#2002)

Sparkle treats a download as a delta only when its file name ends in
`.delta`. The `.sparkle-delta` deltas of 0.8.16 and 0.8.17 failed with "No
valid unarchiver", and every client then downloaded the full DMG.

gpui-updater-release 0.4.4 names them `<dmg>.from-<version>.sparkle.delta`
and refuses a delta URL Sparkle would not apply. Match the new names in the
build artifact upload and the R2 metadata exclude, and let `release appcast`
use the upstream `is_delta_file`.

Co-authored-by: Manus <dev-agent@manus.ai>

* feat(agent): drive the mock agent from a stdin control console (AprilNEA#2003)

feat(agent): drive the mock agent from a stdin control console

openlogi-agent-mock now reads one command per stdin line while the GUI and
overlay stay connected. A developer can set a battery reading, take a device
offline, make its reads and writes fail, show a lock-key or backlight
indicator, move frozen test time, and drop every client connection, all
without hardware.

Battery readings and indicators go through the agent's own state machines.
LowBatteryWatch::take_reading and LockKeyIndicator::announce become the only
public entry points and apply the user's settings, so the orchestrator and the
mock cannot skip them. The mock's observe_backlight is now served by
BacklightOverlayManager, and its demo Caps Lock follows the user's switch and
language.

The console reads stdin on a std thread, because a blocking read on Tokio's
blocking pool cannot be cancelled. Each connection also ends on a shared
disconnect signal, so the overlay's agent-lost path can be tried without
restarting the mock.

fix(agent): refuse a mock time jump past the clock's range

MockClock::advance added the requested time unchecked, so a large enough
`advance` panicked the console task and left the mock without a console.
It now refuses the jump and leaves the clock as it is.

The lock-key platform test assumed every platform but Windows hides Num
Lock. Only macOS does, so Linux CI failed. The test now expects what
`LockKey::is_indicated_here()` gives on the platform it runs on.

* feat(xtask,ci): compose update channel files from per-release records (AprilNEA#2000)

* feat(xtask): compose update channel files from per-release records

Each release now uploads an immutable feed record to releases/<tag>/feed/:
its own latest.json and one single-item appcast per architecture. The new
`cargo xtask release channels` composes every channel file from every
record on R2, so a beta publish moves the beta channel only, and a stable
hotfix published after a newer beta leaves that beta on the beta channel.

- latest-json and appcast write the record into --stage; the manifest's
  channel is the tag's, and an item's sparkle:version is the build version.
- A beta item carries <sparkle:channel>beta</sparkle:channel> and no deltas;
  sparkle-deltas skips a beta tag.
- Channels offer their newest release in Sparkle's order of build versions.
  Items are copied byte for byte, so the signatures stay release appcast's.
- Until a stable release has a record, the current stable channel files
  stand in for it.
- release.yml uploads the record, composes the channel files, and uploads
  them last; the transitional stable-to-beta copy is gone. The version job
  still refuses a beta tag.
- New guard xtask-release-layout-owner: support::update_feed owns the
  releases/<tag>/ layout and the GitHub Release page URL.

* fix(xtask): keep a stopped record upload from blocking later releases

A record's manifest now uploads after its appcasts and marks the record
as complete. `release channels` skips a record directory without its
manifest, so an upload that stopped part way no longer fails every later
publish. A record with its manifest but a file missing is still an error.

The old stable channel files are read only while no stable release has a
record. The channel files are written to a scratch directory and renamed
into place, so a failed write leaves no partial output. The docs now say
that the built-in engine compares release versions, not build versions.

* test(xtask): give the channel tests a fixed pubDate

Without one, each item takes the time it renders at, so two renders a
second apart differ and a byte comparison fails now and then.

* fix(xtask): warn on every beta numbered past the beta channel, accept `dir/.`

The built-in engine and Sparkle also disagree between two betas when the
release PR's version goes down: an app on 0.9.0-beta.3 never gets
0.8.19-beta.10 from the engine. `release channels` now warns whenever a
beta is numbered past the release the beta channel offers, stable or
beta, and prints the warning as a workflow annotation in Actions.

The atomic writer now resolves the output directory before it stages, so
`dir/.` works again. Replacing the current directory is refused.

* test(xtask): let the channels tests pass on Windows

A removed record file fails with the OS's own words, which differ on Windows,
so match fs_err's instead. Win32 drops `missing\..` before it reaches the
disk, so there `missing/..` is the current directory: still refused, with that
message.

* feat(release): build a beta at its own version (AprilNEA#2004)

* feat(release): build a beta at its own version

A beta tags master without a version bump, so its tree carries the stable
release it follows. Each build leg now runs `cargo xtask release
stamp-version` before it compiles, which writes the beta's version into the
workspace manifests and Cargo.lock without committing. The update engine,
the About page, diagnostics, the bundles and the Linux packages then report
the beta's version.

`release version` prints the version to stamp (empty for a stable tag), and
the version job no longer refuses a beta.

* ci(build): let a dispatch build at a beta version

A dry run of a beta build before its tag exists: the Build workflow takes
`stamp_version` on dispatch too. A stamped dispatch only reads sccache,
because its objects serve no other build.

* fix(release): stamp by path, keep Arch betas' version, refuse signed dispatch stamps

Review of AprilNEA#2004:

- `release stamp-version` decided a dependency was a workspace crate's by its
  name, so a registry crate of the same name had its requirement rewritten. It
  now goes by `path`, also stamps `[patch.*]` entries that point at a workspace
  crate, and checks the stamped tree with a full `cargo metadata --locked`. If
  the stamp or the check fails, every file goes back to its bytes.
- nfpm 2.46.3 leaves a semver pre-release out of the Arch `pkgver`, so a beta's
  Arch package said 0.8.18. `linux package` now spells the Arch version
  `0.8.18beta.1` and reads `.PKGINFO` back to check; the Linux leg installs
  `zstd` for that.
- The Flatpak leg's stamp step ran with the workflow's sccache wrapper and no
  toolchain step. It now sets up the toolchain and switches the wrapper off.
- A signed stamped dispatch has no build version, so Sparkle would read its
  `CFBundleVersion` `0.8.18-beta.1` as `0.8.18`. Such a run now fails before
  anything builds.
- DEVELOPMENT.md no longer says the release workflow refuses beta tags.

* docs(release): say which legs stamp and which beta the channel offers

Review of AprilNEA#2004: the MSI leg compiles nothing and has no stamp step, the stamp itself compiles xtask at the old version, the beta channel offers the newest beta above the newest stable release rather than every beta, and signed non-release dispatches do embed Sparkle.

* fix(xtask): edit each manifest once and restore every file a stamp wrote

`stamp` kept its edits by the path it was given, so a root manifest that
is also a member, spelled two ways, was loaded twice; the later write
undid the earlier one, and a compatible requirement still passed
`cargo metadata --locked`. Edits and backups are now keyed by canonical
path, so each file is edited and written once.

Restoring after a failed stamp stopped at the first file it could not
write. It now tries every file and names each one it could not restore.

The docs and workflow comments now say what the code does: restoring is
best effort, the cache comment gives the real reason a stamped dispatch
only reads, the Sparkle refusal names the update range it protects, and
the beta channel's selection, the beta's notes base and the bundle
version fallback are stated as the code implements them.

* fix(device): bound Bolt receiver identity reads (AprilNEA#2009)

Check receiver liveness before optional UID metadata.
Reuse the existing receiver timeouts so missing UID replies preserve readable paired devices and per-slot cache fallback.

Both regressions failed before the fix and passed afterward.
Hardware attribution for AprilNEA#454 and the separate Bluetooth symptoms remain unverified.

Co-authored-by: Manus <dev-agent@manus.ai>

* feat(release): cut betas from a workflow and tell the tap about them (AprilNEA#2005)

* feat(release): cut betas from a workflow and tell the tap about them

Add `.github/workflows/prerelease.yml`, dispatched from `master`. It finds
the open release-plz PR whose head contains the commit, runs
`cargo xtask release next-beta --release-ref <its head>`, and creates the
tag it names with the GitHub App's token, so the push runs release.yml.

`release next-beta` names `v<release>-beta.<N>`: the release PR's workspace
version, numbered by the commits since the stable release before it. It
refuses a release not above that stable release, a bumped but untagged
`master`, and a build version past the MSI limits, as `release version`
does on the pushed tag. It also refuses a commit that is the stable release
or already has a beta, an existing tag, and a tag not above the newest beta
or with the newest beta off the commit's history, so betas only rise.
`ReleaseTag::beta` spells the tag.

release.yml's publish job exports what the beta channel serves. The tap
gets `update-openlogi` for `openlogi@latest` on a stable release, as
before, and a new `update-openlogi-beta` for `openlogi@beta` when a publish
changes the beta channel. A tap without that event ignores it.

* fix(xtask): plan a beta from the HEAD commit, refuse shallow history

`release next-beta` read the workspace version from the working tree and
counted commits in whatever history the clone had. An uncommitted edit
could name a tag that `release version` then rejects on the tagged
commit, and a shallow merge could undercount the beta number.

It now resolves HEAD once and reads the committed manifest, the tags and
the count from that SHA, and refuses a shallow repository. Git-backed
tests cover both cases; disabling either fix fails them.

The docs now say that the workflow tags the commit it was dispatched on,
that the version checks do not promise a build, how pending runs queue,
what the command needs to run locally, and that the event filter, not the
cask, keeps betas out of `openlogi@latest`.

* docs(agents): beta tags come only from prerelease.yml (AprilNEA#2001)

* docs(agents): beta tags come only from prerelease.yml

AGENTS.md said a single v{version} tag, created only by release-plz. Beta
tags v{version}-beta.{N} are release tags too, and prerelease.yml will be
the only place that creates them. Name both owners, and keep "never
hand-create either tag". release-plz.toml's header says the same, and that
release.yml builds and publishes both kinds of tag.

* docs(release-plz): say the release-plz tag is the stable one

* docs(release-plz): a beta needs an open release PR

* fix(deps): update Tokio for AsyncFd soundness advisory (AprilNEA#2019)

Update Tokio 1.53.1 to 1.53.3 for RUSTSEC-2026-0386. Keep existing package versions otherwise; Cargo corrects Windows-only dependency edges while resolving the update.

Co-authored-by: Manus <dev-agent@manus.ai>

* feat(hidpp): add capability-bound force sensing buttons (AprilNEA#2016)

Add the 0x19c0 protocol foundation for adjustable press force. Bind each button to its own endpoint and reported writable range, preserve unknown flags, and separate acknowledgement from read-back.

Co-authored-by: Manus <dev-agent@manus.ai>

* feat(core,agent,gui): add a press force setting for the MX Master 4 Haptic Sense Panel (AprilNEA#2021)

* feat(hidpp): add capability-bound force sensing buttons

Add the 0x19c0 protocol foundation for adjustable press force. Bind each button to its own endpoint and reported writable range, preserve unknown flags, and separate acknowledgement from read-back.

Co-authored-by: Manus <dev-agent@manus.ai>

* feat(device): read and write the haptic panel press force

Builds on the 0x19c0 ForceSensingButton protocol feature. Adds a ForceSensingInfo type and per-device force_sensing config, a force_sensing capability set by the probe, and get/set_force_sensing_on, which take the panel's ForceButton, refuse an unchangeable one, clamp to its reported range, and confirm the write by reading it back.

* feat(agent): serve and re-apply the haptic panel press force

Adds read_force_sensing and set_force_sensing to the agent IPC (protocol v40), re-applies a saved force on reconnect, wake and config reload when the device supports it, and covers the setting in the mock agent, device fixtures and fixture capture.

* fix(device): keep a 0x19c0 probe failure from hiding the haptic panel

A device-answered feature error now reads as an unsupported press force, only Busy or a lost reply leaves the probe incomplete, and the ReprogControls walk always runs.

* feat(desktop): add a Light to Firm press force slider for the haptic panel

Shows a Press force slider under the haptics row when the device's force sensing button is changeable. It spans the device-reported range, starts at the current force, writes on release and saves the force the device reads back.

* fix(desktop): save only the newest confirmed press force

Numbers each press force write the way DPI does, so an answer to a superseded write neither saves nor moves the slider, and only a read-back matching the request is saved. The agent skips reload writes to disabled devices, and the row stays visible with a reading line while a read is retried.

* feat(desktop): move the press force slider to the haptic panel inspector and add a reset

The slider shows in the mouse page's inspector when the Haptic Sense Panel is selected, outside app profiles. A reset button writes the force the mouse reports as its default, read back and saved like a slider release.

* refactor(desktop): read the press force reading from one owner and keep its strings with the pointer

One AppState helper answers whether the active device has a changeable press-force reading; the slider, the commit and the reset all read it. The press-force strings move to the pointer table with the rest of the mouse inspector's, the reset button gains an accessibility label, and the configuration docs name the slider's new place.

* refactor(desktop): share the unsupported-error check and the force sensing test helpers

* fix(device): treat a failed press force read-back as an error

---------

Co-authored-by: AprilNEA <github@sku.moe>
Co-authored-by: Manus <dev-agent@manus.ai>

* feat(core,agent,gui): add guarded disable-keys controls (AprilNEA#993)

* feat(gui): add guarded disable-keys controls

* fix(keyboard): reconcile unconfirmed disable-keys writes

* fix(gui): refresh config projections after disable-keys save retry

* docs(gui): plan disable-keys feedback follow-up

* fix(gui): localize disable-keys feedback and scope control ids

* docs(gui): plan shared retry disabled-state correction

* fix(gui): preserve shared retry disabled styling

Let Button own semantic foreground colors and remove the unused palette argument from retry_line and its callers.

Cover painted light/dark disabled colors, Enter/Space activation and disabled input, plus real-panel Save Retry recovery after a config revision conflict. Add gallery examples and verification evidence.

* fix(deps): update tokio for RUSTSEC-2026-0386

Lock Tokio to 1.53.3 to address the AsyncFd I/O-safety advisory. Preserve all other locked packages and dependency edges. Validation is delegated to GitHub CI because external PR code must not run on this computer.

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(device): gate hidden disable keys descriptors

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(core): bump config schema for disabled keys

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(agent): retain disable keys write ownership

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(agent): isolate disable keys recovery

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(agent): preserve queued disable keys response budget

Start the requester deadline after the owner admits device I/O. Keep the structural guard aligned with the specialized write owner.

Co-authored-by: Manus <dev-agent@manus.ai>

* docs(core): describe disabled keys schema protection

Co-authored-by: Manus <dev-agent@manus.ai>

* feat(ipc): report saved config revision verdict

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(desktop): reconcile stale settings revisions

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(agent): fence write admission after receiver lease

Check the current intent only after waiting for receiver access. Remove stale imports and use named replay construction parts without relaxing lints.

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(device): use feature set descriptor type

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(desktop): invalidate keys after external config reload

Invalidate active and retained snapshots for both general and Disable Keys save acknowledgements. Close writes until the fresh query completes.

Co-authored-by: Manus <dev-agent@manus.ai>

* fix(agent): preserve disable keys transaction ownership

Retain native I/O ownership across discovery and readback, confirm manual intent only on requester receipt, and queue reconciliation reads behind admitted policies. Preserve generic setter replies and distinguish physical replacement from identity enrichment. Add deterministic regressions and owner guards.

* fix(gui): reconcile exact disabled keys config revisions

Correlate coalesced reload receipts with each saved revision and keep editing blocked until the refreshed revision is accepted and reread. Preserve retry state across refresh failures and disconnects. Add stale-receipt, repeated external-edit, and recovery regressions plus an owner guard.

* docs(config): explain disabled keys reconciliation guarantees

* docs: drop disable-keys planning artifacts

The plan and spec files under docs/superpowers/ are working notes from the
implementation. The shipped behavior is described in docs/CONFIGURATION.md
and the user documentation, matching how 75c7e2c retired the AprilNEA#344 artifacts.

* fix(agent-core): guard the write-through keyboard setters

agent-keyboard-write-owner matched set_disable_keys and set_*_on but not
set_disable_keys_write_through_on, the entry point the Disable Keys owner
actually calls. Another agent caller could reach the device setter without
SharedHandles ordering or native completion ownership.

* fix(desktop): name disable-key switches by their action

Each switch is on when its key is disabled, but its accessibility name was
only the key name, so a screen reader announced "Caps Lock, switch, on".
Name the switch "Disable <key>" through a localized catalog entry.

* fix(agent-core): preserve requests across identity enrichment

* fix(agent-core): wake cancelled disable-keys queue waits

* fix(desktop): fence external config adoption until revision confirmation

* docs(config): describe the disable keys fixes

Cover the revision fence for Save Retry and other saves, cancelled queued
requests, direct keyboard identity enrichment, and the switch accessible name.

* test(desktop): end statement closures with semicolons

* fix(desktop): adopt the shared retry line in the press force row

* fix(agent): announce Disable Keys recovery to clients

A recovery restores the keyboard without a 0x4521 report, so the
device-reported settings revision stays put and a client that read the
abandoned mask keeps showing it. Count each started recovery per route
and add it to the published revision. The recovery write already holds
its turn, so the client read that follows waits for it.

* docs(core): note that Disable Keys recovery refreshes the app

* refactor(agent): move Disable Keys recovery dispatch out of the inventory refresh

Keeps refresh_inventory_inner under the too_many_lines limit.

---------

Co-authored-by: AprilNEA <github@sku.moe>
Co-authored-by: Manus <dev-agent@manus.ai>

* fix(i18n): translate the disable-keys strings in 22 locales (AprilNEA#2024)

PR AprilNEA#993 added 25 Disable keys strings and translated them only in Russian. The other 22 catalogs showed English text. Key names follow each catalog's existing key-name convention.

* fix(agent): re-apply volatile settings after replacing a dead channel (AprilNEA#1997)

* fix(agent): re-apply volatile settings after replacing a dead channel

When the enumerator retires a channel for failing probes and later
reopens the node, the device comes back without the published inventory
ever showing it offline: the ledger replays it as online throughout.
`reapply_targets` therefore sees no offline->online transition, and any
`0x1d4b` reconnect broadcast arrives while nothing listens on the new
node. The firmware has lost its volatile settings by then, so DPI and
wheel inversion stay at their defaults until something else re-applies
them.

Track the nodes retired for failing probes and report when a pass opens
a replacement for one. The inventory watcher sends `DeviceWake` before
that pass's snapshot, so the snapshot that publishes the new channel
re-applies volatile settings through the existing reconnect path.

* test(agent): cover DeviceWake ordering after channel replacement

Drive the inventory worker through a direct mouse whose handle dies while its node stays listed: two failed probes retire the channel, and the pass that reopens it must send exactly one DeviceWake immediately before the snapshot that publishes the replacement.

* fix(device): report a replacement only while its node replayed online

A node the OS keeps listing but that never answers again keeps being
retired and reopened: the ledger asks for a fresh channel on every
second failed probe. Each reopen set `replaced_channels_last_tick`, so
the watcher sent `DeviceWake` once per cycle, and the forced re-apply
rewrote every online device's volatile settings and bumped the global
capture re-arm generation about once per recovery period.

The signal is meant for a reconnect no snapshot observed. Ask the
ledger, which owns that fact: report a reopen only if the node's
last-good inventory was still replayed when its channel reopened and is
still published after the pass settles. Once the replay grace expires
the agent has seen the node go offline, and its return re-applies
through the ordinary offline-to-online transition.

* fix(device): keep the replacement wake for a partial live result

The previous commit dropped the replacement signal whenever the ledger
no longer held a last-good inventory after the pass settled. That also
dropped it when the reopening probe failed past the replay grace but
still returned a partial inventory, such as a Bolt receiver with one
unreadable slot. That snapshot keeps publishing the readable devices
online, so no offline-to-online transition would restore their
settings.

Decide on what the pass publishes instead: drop a replacement only when
its settled inventory is empty. A dead channel still publishes nothing
past the grace, so the retire/reopen cycle stays quiet.

* refactor(device): fold the replacement filter into one retain

Clippy's too_many_lines rejected enumerate_reporting_completeness at
101 lines after the previous commit. The same condition fits in one
retain call, which keeps the function at the 100-line limit without
an allow.

---------

Co-authored-by: AprilNEA <github@sku.moe>

* fix(overlay): draw the Windows Actions Ring without a window frame (AprilNEA#1913)

* fix(overlay): draw the Windows Actions Ring without a window frame

GPUI creates WindowKind::PopUp windows with a zero style, which is
WS_OVERLAPPED, and CreateWindowExW gives every overlapped window a
caption. Windows 11 then draws that frame — an opaque backdrop, a thin
border and rounded corners — around the transparent ring and notice.

Make the window a borderless WS_POPUP before placing it, applying the
change with SWP_FRAMECHANGED on the bootstrap move, and ask DWM for
square corners and no border colour.

Fixes AprilNEA#1897

* fix(overlay): keep placing the window when frame removal fails

* style(overlay): space the windows-sys feature list

---------

Co-authored-by: AprilNEA <github@sku.moe>

* fix(windows): post the layout's scan code with keys a layout can move (AprilNEA#2028)

Keys a layout can move now carry the scan code of the key that produces their virtual key under the foreground window's layout. Illustrator matches shortcuts by that scan code under a Russian or Ukrainian layout, and ignored the remapped key without it. The reporter confirmed the fix with the PR build.

Fixes AprilNEA#2026

* fix(cli): route backlight operations through the agent (AprilNEA#2031)

Route `openlogi backlight` through the running agent instead of opening a
competing HID connection. The agent bumps the existing settings revision
after each backlight attempt, so an open GUI reads the keyboard again.

Fixes AprilNEA#2029
Refs AprilNEA#521
Refs AprilNEA#1200

* fix(i18n): translate the receiver chooser, old-pairing cleanup, and update channel in Czech (AprilNEA#2034)

Co-authored-by: Imbecile6197 <335541687+Imbecile6197@users.noreply.github.com>

* feat(desktop): add a keyboard backlight duration timer (AprilNEA#1879)

Keyboards that report HID++ `0x1982` version 3 or later can now read and set how long the keys stay lit after typing stops.

- Device tab: a "Turn off after" row with 5-30 s steps; "Enable extended durations" adds 1 min-2 h steps and writes nothing to the keyboard.
- CLI: `openlogi backlight duration SECONDS` (a multiple of 5, from 5 through 7200), sent through the agent.
- Core/IPC: `BacklightControls` is a bit set with a `DURATION` control; the timer is recorded under protocol v41, and older recorded profiles still load.

Closes AprilNEA#1834

* fix(assets): follow the 0.1 asset release line instead of pinning 0.1.0 (AprilNEA#2039)

* fix(assets): follow the 0.1 asset release line instead of pinning 0.1.0

* docs(assets): describe the release-line asset mirrors

* feat(assets): ask the jsDelivr data API for the newest asset release (AprilNEA#2040)

* feat(assets): ask the jsDelivr data API for the newest asset release

* docs(assets): describe the jsDelivr data API lookup

* fix(assets): keep the range release when the newer jsDelivr release fails

* docs(assets): state the measured jsDelivr cache delays

* chore: release v0.8.18 (AprilNEA#2007)

Co-authored-by: aprilnea[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(flow): complete upstream snapshot merge

---------

Co-authored-by: Xuan Zhang <github@sku.moe>
Co-authored-by: Manus <dev-agent@manus.ai>
Co-authored-by: Hima <19400811+HimaAramona@users.noreply.github.com>
Co-authored-by: Sergey Afonin <safonin@users.noreply.github.com>
Co-authored-by: c1m <2175815055@qq.com>
Co-authored-by: Moon <16745613+MoonZhe@users.noreply.github.com>
Co-authored-by: Libor <jsem@libormacak.eu>
Co-authored-by: Imbecile6197 <335541687+Imbecile6197@users.noreply.github.com>
Co-authored-by: Kabir Singh <26483873+ASparkOfFire@users.noreply.github.com>
Co-authored-by: aprilnea[bot] <263112868+aprilnea[bot]@users.noreply.github.com>
Co-authored-by: aprilnea[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jay <jayboy137@Jay-MacMini.local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file platform: all Cross-platform issue type: build Build, dependency, or local compilation issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants