58d7b649782f75c51f4708b03d77dd6969778afc
1008 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
58d7b64978 |
Merge remote-tracking branch 'origin/main'
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
windows-host / package (push) Has been cancelled
|
||
|
|
b6f59f5000 |
fix(apple): resolve macOS modifiers by keyCode — Control was silently dropped
apple / swift (push) Successful in 1m40s
apple / screenshots (push) Has been cancelled
android / android (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
release / apple (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
Modifier keys arrive only as flagsChanged, and the direction was recovered by diffing the device-dependent L/R bits (NX_DEVICE*KEYMASK) alone. Those bits are undocumented and some keyboards omit them (only the class bit, e.g. NX_CONTROLMASK, is set), so the diff saw no transition and the key never reached the host — no Ctrl shortcuts. SDL/Moonlight key off the event's keyCode for exactly this reason; do the same: keyCode names the changed key, the class bit says up, the device bits (when present) pick the side, and a tracked-held-state flip covers keyboards without them. PUNKTFUNK_INPUT_DEBUG=1 now also logs every flagsChanged (keyCode + raw flags) so a field report is diagnosable from client logs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a041b0aa96 |
fix(host): stop force-disabling zero-copy on Mutter+NVIDIA by default
apply_session_env unconditionally forced PUNKTFUNK_FORCE_SHM=1 for every GNOME/Mutter session, added 2026-06-14 after a same-day stale-frame bug hunt found Mutter has no implicit dmabuf fence on NVIDIA. That override silently contradicted the documented "zero-copy is on by default for all Linux GPU backends" behavior and left Mutter+NVIDIA hosts on the slower CPU/SHM path unconditionally, with no way to opt back in. Live retesting (192.168.1.21, RTX 5070 Ti, real client with cursor movement/window drag/typing — the historical trigger) shows no visible staleness with the override removed. Drop the automatic force; PUNKTFUNK_FORCE_SHM stays as a manual escape hatch for anyone who does hit flashing/stale frames on a Mutter+NVIDIA host. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
7649ccb66b |
feat(host): native AMF SDK encoder for Windows AMD — drop libavcodec
apple / swift (push) Successful in 1m26s
ci / rust (push) Failing after 38s
ci / web (push) Successful in 52s
windows-host / package (push) Successful in 7m26s
apple / screenshots (push) Successful in 6m8s
decky / build-publish (push) Successful in 13s
android / android (push) Successful in 4m58s
arch / build-publish (push) Successful in 5m31s
ci / docs-site (push) Successful in 1m1s
deb / build-publish (push) Successful in 3m20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
ci / bench (push) Successful in 4m52s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m11s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m11s
Direct-SDK AMF encoder (encode/windows/amf.rs), the AMD analogue of the direct-NVENC path, replacing the libavcodec *_amf dispatch. C-vtable FFI pinned to AMF headers v1.4.36, runtime-loaded from the driver's amfrt64.dll (no build feature, no new dependency) exactly as NVENC loads its DLL. - AVC/HEVC (SDR NV12 + 10-bit HDR P010) and AV1 (RDNA3+, probed); a bounded poll retires the libavcodec ~2-frame output hold; native in-place reset(). - Intra-refresh wave (PUNKTFUNK_INTRA_REFRESH), in-band HDR mastering/CLL metadata (*InHDRMetadata -> HEVC SEI / AV1 OBU), and a native codec probe feeding the GameStream advertisement (windows_backend_is_ffmpeg -> windows_backend_is_probed). - AMD dispatch / advertisement / 4:4:4 are native-only; the libavcodec AMF fallback and the PUNKTFUNK_AMF_FFMPEG hatch are removed. FFmpeg serves QSV only (its AMF path retained solely as the latency A/B comparator). - Overload back-pressure: submit bounds in-flight surfaces below the input ring, draining finished AUs (buffered for poll, FIFO-preserved) to free a slot and retry on AMF_INPUT_FULL instead of tearing the encoder down and forcing an IDR; this also closes a latent ring-overwrite corruption seen under load on-glass. Validated on the lab Ryzen iGPU (AMF runtime 1.4.37): HEVC/AVC across a native reset, HEVC Main10 mastering+CLL SEIs byte-verified, intra-refresh accepted, a backpressure burst FIFO-clean, and end-to-end via the macOS client. Measured §5.2 latency A/B: native encode_us p50 ~5 ms (0.31 frame periods) vs libavcodec ~17 ms (1.01). 4:4:4 stays unsupported (VCN hardware limit). Live-gated tests skip cleanly on non-AMD boxes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
efb49c5afd |
feat(windows-client): WOL wait-until-up + IP re-key (Apple/Android parity)
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m9s
apple / swift (push) Successful in 1m26s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m7s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 41s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 46s
apple / screenshots (push) Successful in 5m42s
android / android (push) Successful in 5m22s
arch / build-publish (push) Successful in 6m57s
ci / web (push) Successful in 57s
ci / rust (push) Successful in 5m20s
ci / docs-site (push) Successful in 1m1s
deb / build-publish (push) Successful in 3m20s
decky / build-publish (push) Successful in 13s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m50s
flatpak / build-publish (push) Successful in 4m1s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m22s
docker / deploy-docs (push) Successful in 6s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m39s
Like the Linux client, the Windows client had WOL send + MAC storage + a Wake action + fire-and-forget auto-wake, but no poll-until-up + IP re-key. Add the polished flow (mirrors Apple HostWaker + the request_access screen pattern): - connect::wake_and_connect — send the magic packet, show a cancelable Screen::Waking busy page, poll discovery::browse() until the host reappears (re-sending every 6 s, 90 s budget), then dial; re-key the saved host (KnownHosts::upsert) if it woke on a new IP. - Screen::Waking + waking_page, routed in app/mod.rs (mirrors RequestAccess). - the saved-host tile routes an offline-with-MAC tap to wake_and_connect; MENU_WAKE stays a pure send-only button. Reviewed against the request_access reference — DiscoveredHost/KnownHost/Target types, the widgets, .call()/.lock(), and the initiate signature all match; compile-verified by Windows CI (no local Windows toolchain). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a5254c8798 |
feat(linux-client): WOL wait-until-up + IP re-key (Apple/Android parity)
The Linux client already had WOL send + MAC storage + a Wake action + auto-wake- on-connect, but the auto-wake just fired a packet and did one dial to the stored address — so a host that woke on a new DHCP lease failed, and there was no "waiting" feedback. Add the polished flow (mirrors Apple/Android HostWaker): - ui_trust::wake_and_connect — send the magic packet, poll mDNS until the host reappears (re-sending every 6 s, 90 s budget) behind a cancelable "Waking…" dialog, then connect; if it woke on a new IP, re-key the saved host first. - trust::rekey_addr — no-churn addr/port update keyed by fingerprint. - the hosts page routes an offline saved-host-with-MAC tap to on_wake_connect (the new flow) instead of fire-and-forget wake + immediate dial. Builds + clippy + fmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6081502949 |
feat(clients): signal explicit exit (QUIT_CLOSE_CODE) on deliberate disconnect
apple / swift (push) Successful in 1m10s
android / android (push) Successful in 5m5s
arch / build-publish (push) Successful in 5m28s
ci / web (push) Successful in 1m10s
windows-host / package (push) Successful in 7m9s
ci / docs-site (push) Successful in 1m21s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m19s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m11s
release / apple (push) Successful in 8m40s
ci / rust (push) Successful in 4m58s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 49s
apple / screenshots (push) Failing after 1m12s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 53s
ci / bench (push) Successful in 5m2s
decky / build-publish (push) Successful in 13s
deb / build-publish (push) Successful in 3m22s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
flatpak / build-publish (push) Successful in 4m18s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 12m3s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m1s
docker / deploy-docs (push) Successful in 18s
The core's deliberate-quit close (NativeClient::disconnect_quit → QUIT_CLOSE_CODE,
host skips the keep-alive linger) was implemented but never called by any client.
Wire it to each client's explicit user-disconnect action — NOT to a network drop /
host-ended / app-background (those keep the linger for a reconnect):
- core: new C-ABI punktfunk_connection_disconnect_quit(c) for the ABI clients
- Linux (direct-core): Ctrl+Alt+Shift+D + the controller escape chord
- Windows (direct-core): Ctrl+Alt+Shift+D
- Apple (C-ABI): PunktfunkConnection.disconnectQuit() + a `deliberate` flag on
SessionModel.disconnect() (sessionEnded passes false → keeps the linger)
- Android (JNI): new nativeDisconnectQuit export, called from the back gesture +
the Select+Start+L1+R1 chord (not the host-gone watchdog)
- probe already did this via --quit (
|
||
|
|
a2723e34a1 |
style: rustfmt drift from the AMF/watchdog commits
apple / swift (push) Successful in 1m32s
android / android (push) Successful in 4m57s
arch / build-publish (push) Successful in 5m42s
ci / web (push) Successful in 1m4s
windows-host / package (push) Successful in 7m57s
ci / docs-site (push) Successful in 1m22s
apple / screenshots (push) Successful in 6m50s
ci / rust (push) Successful in 4m55s
ci / bench (push) Successful in 4m54s
deb / build-publish (push) Successful in 3m24s
decky / build-publish (push) Successful in 15s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m44s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m51s
docker / deploy-docs (push) Successful in 19s
`cargo fmt --all --check` (a CI gate) failed on main: config.rs (the new
`zerocopy: val(...).map { !matches!(...) }` from
|
||
|
|
8df6d07cc6 |
fix(android): launch games from the library
The library browser was browse-only — the A button (and a tap) did nothing. Wire it to connect + boot straight into the selected title: thread a `launch` id (the store-qualified library id `steam:<appid>` / `custom:<id>`) through nativeConnect → NativeClient's Hello.launch (was hardcoded None), add a shared connectToHost() the ConnectScreen and the library launcher both use, and have LibraryScreen dial the host with launch=game.id on A / tap — with a launching overlay + an "A Launch" hint. Verified: native compiles (cargo-ndk arm64), app+kit Kotlin compiles (gradle, 3 ABIs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2c1bb4de93 |
docs(design): native AMF encoder handoff — drop ffmpeg for AMF, keep for QSV
apple / swift (push) Successful in 1m13s
android / android (push) Failing after 2m16s
ci / rust (push) Failing after 40s
ci / web (push) Successful in 53s
apple / screenshots (push) Failing after 3m21s
ci / docs-site (push) Successful in 1m0s
arch / build-publish (push) Successful in 5m17s
windows-host / package (push) Successful in 7m30s
deb / build-publish (push) Successful in 3m19s
decky / build-publish (push) Successful in 13s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
ci / bench (push) Successful in 4m51s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m39s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m15s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 47s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m47s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m33s
docker / deploy-docs (push) Successful in 20s
Design + decision record for replacing the libavcodec *_amf path with a direct AMF SDK encoder (encode/windows/amf.rs, the AMD analogue of the direct NVENC path). Motivation is measured, not speculative: the libavcodec wrapper structurally holds ~2 frames (36 ms p50 at 720p60 on VCN, un-tunable), driver wedges surface as forever-EAGAIN instead of typed AMF_RESULTs, and intra-refresh / in-band HDR SEI are inexpressible through it. Covers the C vtable FFI strategy (amfrt64.dll runtime-load, FFmpeg amfenc.c and OBS texture-amf.cpp as references), bounded-poll retrieval, the property table, watchdog/reset interplay, exact dispatch seams, a lab-iGPU validation plan with today's zero-copy baselines, and three phases ending with the ffmpeg-AMF arm deleted (FFmpeg stays QSV-only). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8fb126482e |
feat(host): default the Windows AMF encode input to zero-copy D3D11
On-glass A/B on the Ryzen 7000 iGPU (1080p120 HDR P010, hevc_amf,
PUNKTFUNK_PERF stage split): the system-memory readback costs the encode
thread 2.7-2.9 ms p50 (6.6 ms p99) per frame in submit; the zero-copy D3D11
pool path does the same work in 0.26 ms p50 (0.5 ms p99) — and on an iGPU the
readback also burns the shared memory bandwidth the game needs. The docs-site
already promised "on by default ... D3D11 on Windows" since the Linux flip
(
|
||
|
|
06d594bc2a |
fix(host): encode-stall watchdog — heal the silent AMF/QSV freeze in place
Field reports: Windows AMD/Intel streams freeze after ~3-5 min regardless of desktop activity. Root cause: the libavcodec AMF/QSV poll is non-blocking (EAGAIN -> Ok(None)), and the encode loop's drain treated None as benign without popping `inflight` — a wedged driver (QueryOutput stops producing) meant frames kept being submitted, inflight grew unboundedly, no AU ever reached the send thread, and nothing logged: a silent permanent freeze. The input-side twin: once libavcodec's one-frame buffer fills, avcodec_send_frame EAGAINs and the submit `?` killed the whole session. Add `Encoder::reset()` (in-place encoder rebuild; implemented for AMF/QSV by dropping the wedged libavcodec encoder so the next submit re-opens it on the current device, forced IDR) and an encode-stall watchdog in the stream loop: trip on a poll error, on no AU within max(2 s, 8 frame intervals) while frames are owed, or on an owed backlog worth more than the window's frames (the slow-leak latency-runaway form). Recovery is a bounded (5 consecutive, cleared by any delivered AU) in-place rebuild + forced IDR — a logged ~one-second hiccup instead of a dead stream; exhaustion or a reset-less backend still fails the session with a clear error. Submit failures route through the same bounded recovery. The three existing pipeline-rebuild paths (session switch, mode switch, capture loss) now also clear the stale in-flight records that pointed at the dropped encoder. Backends whose poll blocks (direct NVENC sync, software) can't false-trip: they never return Ok(None) mid-stream and drain inflight below depth each tick. Validated: clippy -D warnings (nvenc,amf-qsv), 191 host tests, synthetic E2E 300/300 frames, and an on-glass AMD iGPU session (1080p120 HDR hevc_amf). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
39889c3102 |
fix(host): silence write-only cur_node_id on non-Linux encoder builds
apple / swift (push) Successful in 1m10s
android / android (push) Successful in 6m0s
arch / build-publish (push) Successful in 6m5s
ci / web (push) Successful in 1m1s
windows-host / package (push) Successful in 7m17s
apple / screenshots (push) Successful in 6m43s
ci / docs-site (push) Successful in 1m18s
ci / bench (push) Successful in 4m58s
ci / rust (push) Successful in 9m27s
decky / build-publish (push) Successful in 26s
deb / build-publish (push) Successful in 6m37s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4m9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 28s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m41s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m17s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 53s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m30s
docker / deploy-docs (push) Successful in 24s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m17s
cur_node_id (the capture 5-tuple's node id, added for the Linux dedicated- game-exit check) is read only under #[cfg(target_os = "linux")], so on the Windows nvenc/amf-qsv build it was assigned but never read — failing `clippy -D warnings`. Read it on non-Linux platforms (the `let _ = &launch` idiom already used in this file). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
215a8aa9dc |
chore(release): bump workspace version to 0.8.1
windows / build (aarch64-pc-windows-msvc) (push) Has been cancelled
windows / build (x86_64-pc-windows-msvc) (push) Has been cancelled
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Has been cancelled
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Has been cancelled
windows-host / package (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
release / apple (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
decky / build-publish (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
audit / cargo-audit (push) Has been cancelled
audit / bun-audit (push) Has been cancelled
apple / swift (push) Has been cancelled
deb / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
arch / build-publish (push) Has been cancelled
apple / screenshots (push) Has been cancelled
android / android (push) Has been cancelled
Release 0.8.1: game-mode + dedicated game sessions, zero-copy GPU import process-isolation (and zero-copy on by default on all backends), user-defined custom display presets, and a physical-monitor refresh-preservation fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2f9e61d191 |
feat(host): enable GPU zero-copy by default on all backends
apple / swift (push) Failing after 45s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m15s
android / android (push) Successful in 4m56s
windows-host / package (push) Failing after 3m31s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Has been cancelled
windows / build (aarch64-pc-windows-msvc) (push) Has been cancelled
windows / build (x86_64-pc-windows-msvc) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
arch / build-publish (push) Successful in 5m39s
release / apple (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
apple / screenshots (push) Has been skipped
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
decky / build-publish (push) Has been cancelled
ci / web (push) Successful in 1m3s
ci / docs-site (push) Successful in 1m23s
ci / rust (push) Successful in 4m46s
ci / bench (push) Successful in 4m57s
deb / build-publish (push) Successful in 4m22s
Now that the per-capture worker subprocess makes an NVENC EGL/CUDA driver fault survivable (design/zerocopy-worker-isolation.md), the reason the NVENC zero-copy path stayed opt-in is gone. zerocopy::enabled() now defaults ON for both GPU backends (was ON VAAPI / OFF NVENC). Fallbacks are intact: VAAPI's one-shot CPU auto-downgrade (VAAPI-gated, never trips for NVENC) and NVENC's per-capture fallback + worker-death latch. Reframe the shipped host.env examples and setup guides to rely on the default rather than force PUNKTFUNK_ZEROCOPY=1 (an explicit =1 skips the VAAPI auto-downgrade). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a947f48d29 |
fix(host): preserve a physical monitor's refresh when adding a virtual display
Connecting reset an existing physical monitor's refresh (e.g. 120->60 Hz) because the topology code read the physical's mode AFTER the virtual output perturbed the compositor layout — by which point it had already been downgraded. Read/preserve each physical's mode from a pre-connect snapshot. - Mutter: build_primary_keeping_physicals takes the pre-virtual snapshot and preserves each physical's real mode (pick_keep_mode, unit-tested) - KWin: capture each output's mode when disabling for exclusive, re-assert it on re-enable (a bare enable defaulted to ~60 Hz) - Windows: skip the refresh-resetting SDC_TOPOLOGY_EXTEND when a physical is already active Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a4f81dec48 |
feat(host): user-defined custom display presets
Save named bundles of the display-management policy (the six behavior axes
plus the game-session axis) as custom presets, alongside the built-ins. A
custom preset is data — stored in <config>/display-presets.json — not a Preset
enum variant, so DisplayPolicy::effective() stays pure and the built-in set is
untouched; applying one writes a Custom policy via the existing PUT
/display/settings.
- policy.rs: CustomPreset/CustomPresetInput + load/add/update/delete store
- mgmt.rs: GET/POST /display/presets + PUT/DELETE /display/presets/{id},
surfaced on GET /display/settings
- web console: custom-preset cards with save-as / edit / delete + i18n
- regenerated api/openapi.json; docs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
077d8f85ca |
feat(host): isolate the zero-copy GPU import in a worker process
The tiled EGL/GL→CUDA import crashed the whole host (SIGSEGV inside libnvidia-eglcore via cuGraphicsMapResources) when the compositor invalidated an imported dmabuf mid-map — reproduced on the Bazzite F44 Game→Desktop switch (design/zerocopy-hardening-handoff.md). A driver SIGSEGV is uncatchable in-process, so the whole EglImporter (tiled EGL/GL→CUDA and LINEAR Vulkan→CUDA) now runs in a per-capture `zerocopy-worker` subprocess: dmabuf fds go over a SEQPACKET socketpair (SCM_RIGHTS, sent once per buffer keyed by dmabuf st_ino; NeedFd resend self-heals cache desync), frames come back as CUDA-IPC pooled device buffers (still zero-copy, +one socket RTT/frame). Worker death poisons the capturer so the existing capture-loss rebuild runs — the host survives; 3 consecutive deaths latch the GPU import off (CPU/SHM path). PUNKTFUNK_ZEROCOPY_INPROC=1 keeps the old in-process import for debugging/A-B. Also fixed along the way: a failed *tiled* import no longer falls through to the CPU mmap de-pad (which scrambled tiled bytes; LINEAR keeps the fallback); Nv12Blit dropped its GL textures while still CUDA-registered (unregister now runs first); GlBlit had no Drop at all (GL objects leaked per size change); VkBridge's per-fd src cache is now invalidated on renegotiation/eviction instead of never. Design: design/zerocopy-worker-isolation.md. Unit tests: 14 new (protocol fd-passing, worker dispatch, client handshake/death/NeedFd, death latch). On-glass validated on the RTX 5070 Ti/GNOME box (.21): the worker path streams at p50 1.30 ms (NV12, 1800 frames 0-mismatched, parity with the in-process path), and a kill -9 of the worker mid-stream is survived by the host and recovered — poison -> capture lost, rebuilding pipeline in place -> a fresh worker in ~185 ms -> streaming resumes (2385 frames, 0 mismatched). A real KWin compositor-crash repro is still pending (a worker kill -9 is strictly harsher, so it corroborates). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
07d46f865c |
docs: zero-copy EGL/CUDA capture-crash hardening handoff
Describes a reproduced host SIGSEGV in cuGraphicsMapResources (inside libnvidia-eglcore), reached via zerocopy::cuda / zerocopy::egl on the tiled EGL/GL->CUDA capture path, when the KWin dmabuf is invalidated mid-map (observed on .181 during a Game->Desktop switch under zero-copy, with the compositor itself crashing). Pre-existing capture-layer issue, not the gamemode work. Issue description + root cause + solution-space considerations only -- the next agent plans the implementation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1271fd5ea2 |
feat(host): game-mode integration + dedicated game sessions
Implements design/gamemode-and-dedicated-sessions.md (Parts A1-A5 + B0-B2):
reconciles the merged display-management registry with session-mobile
Bazzite/SteamOS hosts and adds a per-launch dedicated gamescope mode.
- A1 DisplayOwnership {Owned,External,SessionManaged} + poolable_now(): the
registry pools only what it owns, so gamescope managed/attach outputs are no
longer double-owned by the registry AND the gamescope restore worker (fixes
the game-mode-reconnect stale-node wedge).
- A2 validated reuse: (backend,mode,launch,epoch) reuse key + kept_display_alive
liveness probe + reused_gen/mark_failed on a reused-display first-frame failure.
- A3 policy-driven managed restore (keep_alive replaces the hardcoded 5s debounce;
forever = held = gaming-rig truthful) + crash-restore persist + SIGKILL teardown
(kill_unit, applied to our transient unit AND the autologin stop -- validated
live on .181 to avoid the F44 GPU-context leak).
- A4 session epoch: observe_session_instance bumps the epoch + invalidate_backend
on a desktop-compositor instance change; gamescope spawns are exempt.
- A5 per-spawn log + PID-scoped gamescope node discovery.
- B0 game_session {auto,dedicated} policy (top-level, preset-orthogonal) +
pick_gamescope_mode dedicated_launch + steam -silent command shaping.
- B1 free the autologin Steam before a dedicated Steam spawn (single-instance).
- B2 game-exit -> APP_EXITED_CLOSE_CODE (0x52) clean session end.
Adversarially reviewed (11 findings fixed). Validated on glass (.181 Bazzite F44,
RTX 4090): dedicated spawn streams a real game smoothly; keep-alive reuse; the
SIGKILL fix avoids the F44 vkCreateDevice leak. Workspace green
(build / test --workspace / clippy -D warnings / fmt), OpenAPI + C header
regenerated, web console tsc + vite build green. clients/probe: bump the
no-video timeout 8s->45s for gamescope cold starts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
42b45113a9 |
fix(android): pass dropped streams through to the ui
android / android (push) Has been cancelled
apple / screenshots (push) Has been cancelled
apple / swift (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
ci / rust (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
release / apple (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Has been cancelled
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Has been cancelled
windows-host / package (push) Has been cancelled
windows / build (aarch64-pc-windows-msvc) (push) Has been cancelled
windows / build (x86_64-pc-windows-msvc) (push) Has been cancelled
|
||
|
|
d76a42e0e9 |
docs(security): add 2026-07-05 whole-project posture audit
android / android (push) Has been cancelled
apple / screenshots (push) Has been cancelled
apple / swift (push) Has been cancelled
arch / build-publish (push) Has been cancelled
audit / bun-audit (push) Has been cancelled
audit / cargo-audit (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
windows-host / package (push) Has been cancelled
Assessment of the overall security architecture, the state of the prior reviews' remediations, and the process/supply-chain controls. Flags the two web-console residuals (no brute-force throttle; cookie seal key from the login password) that the accompanying web-hardening change fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5a51b0d8e7 |
ci: SHA-pin secret-bearing third-party actions + audit the web dep tree
- Pin android-actions/setup-android, appleboy/scp-action, and appleboy/ssh-action to commit SHAs (version kept in a trailing comment). These run in jobs holding the Android signing keystore, Play service-account, and deploy SSH key, so a moved tag on a third-party action could exfiltrate them. - Add a bun-audit job to audit.yml over web/bun.lock — the console holds the login gate, session sealing, and mgmt token, so its deps matter too — and trigger the workflow on web/bun.lock changes alongside Cargo.lock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
bda5556d37 |
feat(web): harden login gate — throttle, scoped TLS, token-derived seal key
Remediates the two web-console residuals from the 2026-07-05 posture audit: - Brute-force throttle (loginThrottle.ts): per-IP exponential backoff after 5 free attempts, plus a global floor for spread-out floods, keyed on the socket peer IP (not spoofable X-Forwarded-For) with a size-capped map. The constant-time compare already stopped the timing leak; this bounds guess *volume* against a by-design LAN-exposed console. - Session seal key now derives from the high-entropy mgmt token instead of the low-entropy login password, so a captured cookie is no longer an offline password oracle. Falls back to the password only when no token is configured (dev/local). Rotating the token now invalidates sessions. - Replace the process-wide NODE_TLS_REJECT_UNAUTHORIZED=0 with per-request Bun TLS scoped to the loopback proxy hop; a non-loopback mgmt URL now verifies normally. Dropped the env var from the systemd unit, Steam Deck installer, Windows run scripts, env examples, and web README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ab56536842 |
docs(readme): Windows host capture is IDD-push, not DXGI/WGC
The DXGI Desktop Duplication + WGC relay paths were removed; sealed IDD-push (finished frames pushed straight into the host's own IddCx driver, no screen-scraping) is now the sole Windows capture path. Fix the stale "DXGI/WGC capture" claims in the root and punktfunk-host READMEs, which also contradicted the push-based IDD description already present in the root README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
27c53a4b53 |
perf(android): low-latency decode overhaul — vendor keys, async loop, system tuning
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 9m21s
Close the latency gap on the Android client with per-SoC decoder tuning, an event-driven decode loop, and full system integration. - Decoder selection: rank MediaCodecList decoders in Kotlin (hardware/vendor preferred, software avoided, FEATURE_LowLatency probed) and create the chosen one by name. Per-SoC low-latency keys gated on the codec-name prefix: Qualcomm picture-order + low-latency, Exynos (also Google Tensor), Amlogic, HiSilicon; MediaTek vdec-lowlatency set unconditionally. operating-rate = MAX (Qualcomm) vs priority = 0 (else) are mutually exclusive. NVIDIA/Rockchip/Realtek have no vendor key — covered by ranking + the standard low-latency key. - Async decode loop: AMediaCodec async-notify replaces the poll loop, presenting a decoded frame the instant it is ready instead of waiting out a poll interval. Behind USE_ASYNC_DECODE with the synchronous loop kept for A/B during bring-up. - System integration: Wi-Fi FULL_LOW_LATENCY lock and HDMI ALLM (setPreferMinimalPostProcessing) for the stream's lifetime; game_mode_config.xml opting out of OEM downscaling / FPS overrides. - Pipeline: boost the data-plane pump + audio thread priorities, AAudio usage=Game, DSCP marking on by default on Android, ADPF setPreferPowerEfficiency(false), and setFrameRateWithChangeStrategy(ALWAYS) to force the HDMI mode switch on TV. - lowLatencyMode master toggle (default on) as the escape hatch; the stats HUD now shows the resolved decoder name. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
69fcb6e0b1 |
docs: restructure host setup by distro, configuration by compositor
apple / swift (push) Successful in 1m8s
apple / screenshots (push) Successful in 5m33s
android / android (push) Successful in 4m43s
arch / build-publish (push) Successful in 5m38s
ci / web (push) Successful in 1m3s
ci / docs-site (push) Successful in 1m17s
ci / rust (push) Successful in 4m48s
ci / bench (push) Successful in 5m7s
decky / build-publish (push) Successful in 14s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
deb / build-publish (push) Successful in 4m29s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m16s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m24s
docker / deploy-docs (push) Successful in 6s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m3s
Split the docs' single distro×desktop axis (ubuntu-gnome / ubuntu-kde / fedora-kde) into two,
which deduplicates the shared mechanics and scales to distros that run several desktops (Arch):
- Install the host — per distro/OS (ubuntu, fedora, arch, bazzite, steamos-host, windows-host):
GPU driver + package + input group, then a canonical "Configure your desktop" funnel.
- Configure your desktop — per compositor (kde, gnome, gamescope, sway): host.env, compositor
quirks, the headless session, and starting the host.
New shared web-console page (enable · login password · arm pairing) removes the console/password
block that was copy-pasted across all seven host pages. Merged ubuntu-gnome + ubuntu-kde into
ubuntu; renamed fedora-kde to fedora; kept bazzite and steamos-host as dedicated appliance guides
(trimmed of duplication). Moved the KWin headless session, the GNOME EGL/lock traps, and the
gamescope attach/managed model out of the distro pages onto their compositor pages.
Fixed while restructuring: distro-specific paths on kde (kde-desktop-setup.sh is Fedora/Bazzite-only;
the .deb ships host.env.kde under /usr/share/punktfunk-host), the interactive "start the host" step
that was lost in the merge, sway over-claiming Hyprland, and a pre-existing broken anchor in
how-it-works.
Removal of the three old pages was captured by the preceding commit
|
||
|
|
8ebb61400c |
fix(web): clearer topology/identity copy, capped description width, mobile More-nav, preset spacing
apple / swift (push) Successful in 1m12s
apple / screenshots (push) Successful in 5m18s
windows-host / package (push) Successful in 7m38s
android / android (push) Successful in 12m11s
arch / build-publish (push) Successful in 9m7s
ci / web (push) Successful in 1m7s
ci / docs-site (push) Successful in 1m18s
ci / rust (push) Successful in 4m47s
ci / bench (push) Successful in 5m3s
decky / build-publish (push) Successful in 19s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 32s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
deb / build-publish (push) Successful in 4m31s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 57s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m48s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m28s
docker / deploy-docs (push) Successful in 20s
Console polish on the Virtual displays card + shell: - Topology help now leads with the streamed display's role (Extend/Primary/Exclusive) instead of the confusing physical-monitor-only framing; notes the headless case. Identity help spells out the actual behavior (stable per-client identity → the desktop reapplies that client's scaling/resolution on reconnect) + what Shared / Per-client / Per-client+resolution each do. - Cap description/help width at max-w-prose so long help text isn't a full-viewport line on large screens. - Mobile bottom nav: 8 flat tabs were too cramped → 4 pinned tabs + a "More" tab whose sheet holds the rest (Performance/Logs/Pairing/Settings), "More" highlighted when the active route is in the overflow. - More breathing room under the "Preset" heading. web tsc + biome + vite build green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b57e414618 |
chore(release): bump workspace version to 0.8.0
apple / swift (push) Successful in 1m10s
audit / cargo-audit (push) Successful in 1m23s
ci / web (push) Successful in 1m7s
ci / docs-site (push) Successful in 1m23s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 3m58s
release / apple (push) Successful in 9m58s
ci / bench (push) Successful in 4m55s
ci / rust (push) Successful in 8m57s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 4m18s
apple / screenshots (push) Successful in 5m55s
windows-host / package (push) Successful in 7m56s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m19s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m16s
android-screenshots / screenshots (push) Successful in 2m29s
arch / build-publish (push) Successful in 5m11s
decky / build-publish (push) Successful in 19s
android / android (push) Successful in 4m36s
flatpak / build-publish (push) Successful in 5m7s
linux-client-screenshots / screenshots (push) Successful in 6m15s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m14s
web-screenshots / screenshots (push) Successful in 2m40s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m45s
docker / deploy-docs (push) Successful in 7s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 8s
deb / build-publish (push) Successful in 4m21s
The [workspace.package] version (inherited by every crate via version.workspace) is the release being cut; refresh the 9 workspace entries in Cargo.lock to match (CI builds --locked). Canary derives from the tag (scripts/ci/pf-version.sh), so cutting v0.8.0 auto-advances canary to 0.9.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>v0.8.0 |
||
|
|
ec40a4062f |
build: pin the exact Rust toolchain (1.96.0) to stop rustfmt drift
apple / swift (push) Successful in 1m23s
arch / build-publish (push) Successful in 5m56s
android / android (push) Successful in 6m38s
apple / screenshots (push) Successful in 5m50s
ci / web (push) Successful in 1m10s
ci / docs-site (push) Successful in 1m27s
ci / bench (push) Has been cancelled
ci / rust (push) Has been cancelled
decky / build-publish (push) Successful in 14s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 7s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 6s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 7s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 55s
windows-host / package (push) Successful in 14m52s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
deb / build-publish (push) Has been cancelled
rust-toolchain.toml pinned the floating "stable" channel, so the CI image baked whatever stable existed at image-build time. When the image is rebuilt onto a newer stable, rustfmt's rules shift and `cargo fmt --all --check` fails on files nobody touched — the recurring format-drift that keeps red-lighting CI. Pin channel = "1.96.0" (== today's stable: rustc ac68faa20, rustfmt 1.9.0-stable), the exact build CI already runs, so this is a no-op now but locks formatting for good: local dev, the Linux CI image, and the Windows runner all use rustup and honor this file, so they converge on one rustfmt. Formatting now only changes in a deliberate bump-this-pin- and-reformat commit. ci.yml cache comment updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
19c35de3d7 |
style(host): cargo fmt --all (rustfmt 1.9.0 drift)
The CI image's rustfmt reformats these files (multi-line assert!/tracing! macros, match-arm and struct-variant wrapping) — pre-existing drift that the Format job caught. Reformat to match. Pure formatting; no logic change. main.rs also gets a blank line before a standalone comment so rustfmt stops mis-indenting it as a trailing-comment continuation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
aa012c6b45 |
feat(vdisplay/mutter): pin the client's refresh by default; drop PUNKTFUNK_MUTTER_VIRTUAL_REFRESH
The >60 Hz virtual-monitor path (RecordVirtual "modes" with the client's exact WxH@Hz) was gated behind PUNKTFUNK_MUTTER_VIRTUAL_REFRESH, default OFF, after a high-refresh virtual CRTC SIGSEGV'd gnome-shell on session teardown. That crash was since fixed by stopping the screencast before any monitor reconfig, so the gate is dead weight — and a silent footgun: every non-headless GNOME client was capped at Mutter's PipeWire-derived 60 Hz unless they knew the hidden flag. Make it the default: the custom-mode path now runs whenever mode.refresh_hz > 60 (≤60 Hz stays byte-identical to before — Mutter's 60 Hz default is already correct), and the virtual_refresh_enabled() env read is removed. Docs updated (configuration.md env table, vrr-plan.md reference). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
74c9e46faf |
fix(vdisplay/windows): Windows clippy — per-block SAFETY comments + then_some
apple / swift (push) Successful in 1m10s
android / android (push) Successful in 4m38s
ci / rust (push) Failing after 30s
arch / build-publish (push) Successful in 5m25s
ci / web (push) Successful in 49s
ci / docs-site (push) Successful in 59s
apple / screenshots (push) Successful in 5m37s
windows-host / package (push) Successful in 7m54s
deb / build-publish (push) Successful in 3m1s
decky / build-publish (push) Successful in 14s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
ci / bench (push) Successful in 5m34s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m16s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m6s
The branch's Windows-host code never ran through the fleet Windows clippy (kept off CI); the merge to main exposed it. Fix the 4 -D warnings failures in cfg(windows) code: - manager.rs: 3 unsafe blocks (isolate_displays_ccd / force_extend_topology / set_virtual_primary_ccd) had one "both arms" SAFETY comment on the `match` line — clippy::undocumented_unsafe_blocks wants it immediately before each block. Split into per-block SAFETY comments. - win_display.rs: `.then(|| …)` on a POD u32 union read → `.then_some(…)` (eager is fine, discarded when false) for clippy::unnecessary_lazy_evaluations. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
95b3496bb5 |
merge: display-management (Stages 0-5 §6A + keep-alive hardening + gaming-rig)
apple / swift (push) Successful in 1m15s
windows-host / package (push) Failing after 3m56s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m18s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m20s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 57s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 1m2s
release / apple (push) Successful in 8m43s
android / android (push) Successful in 4m17s
ci / rust (push) Failing after 29s
ci / web (push) Successful in 49s
arch / build-publish (push) Successful in 5m33s
ci / docs-site (push) Successful in 59s
apple / screenshots (push) Successful in 5m42s
deb / build-publish (push) Successful in 3m7s
decky / build-publish (push) Successful in 14s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 28s
ci / bench (push) Successful in 4m41s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 44s
flatpak / build-publish (push) Successful in 4m30s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m21s
docker / deploy-docs (push) Successful in 20s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m25s
Merges display-mgmt-stage0 — the user-configurable virtual-display policy layer above the
per-compositor backends. On-glass validated (KWin .116 + Mutter .21; Windows compile-verified .173):
- Policy surface (keep_alive · topology · conflict · identity · layout · max) →
display-settings.json, console-editable via /api/v1/display/{settings,state,release,layout} + a
dedicated "Virtual displays" console section. All five axes enforced, not just stored.
- Lifecycle: pure state machine + Linux keep-alive pool (registry + DisplayLease ownership split),
incl. keep_alive=forever/Pinned (freed via /display/release); topology extend/primary/exclusive
(group-aware); per-client identity (KWin per-slot names → KDE scaling round-trips); mode_conflict
admission (Windows default reject, single-capturer IDD); §6A multi-monitor (display groups +
layout engine + console arrangement table — several clients as monitors of one desktop).
- Keep-alive reconnect hardened: same-client zombie preempt (never a 2nd display), deliberate-quit
skip-linger (QUIT_CLOSE_CODE), tunable idle timeout (PUNKTFUNK_IDLE_TIMEOUT_MS).
Conflicts (packaging/{arch,debian}/README.md firewall docs): kept main's ufw/nft port commands +
the branch's --data-port documentation. build + clippy -D warnings + cargo test --workspace
(18 suites, 0 failed) green on the merged tree.
|
||
|
|
334f36ce25 |
test(punktfunk1): serialize in-process-host tests (shared admission table)
The reconnect-preempt ( |
||
|
|
88348153f3 |
feat(apple): wake-until-up overlay + host edit with MAC prefill
apple / swift (push) Successful in 1m10s
arch / build-publish (push) Successful in 5m17s
android / android (push) Successful in 7m30s
ci / web (push) Successful in 1m7s
ci / docs-site (push) Successful in 1m11s
release / apple (push) Successful in 8m39s
ci / rust (push) Successful in 4m53s
deb / build-publish (push) Successful in 2m58s
decky / build-publish (push) Successful in 16s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m50s
apple / screenshots (push) Successful in 5m44s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m9s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m52s
- HostWaker + WakeOverlay: after sending the Wake-on-LAN packet, wait until the host is really back (resend + mDNS poll, timeout, cancel/retry) before connecting. macOS-only in practice — WoL stays gated off on iOS/tvOS pending the multicast entitlement. - Add/Edit host sheet gains a Wake-on-LAN MAC field, prefilled from the stored MAC or the live mDNS advert; parseMacs validates aa:bb:cc:dd:ee:ff. - Gamepad chrome/home and glass-style polish. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4a87cef98c |
feat(android): console UI, wake-on-LAN wait-until-up, host edit + TV/tablet polish
Bring the Android client to parity with Apple's gamepad experience and finish Wake-on-LAN. - Console/gamepad home: host carousel, aurora chrome, mTLS game-library coverflow, and an input-aware legend that switches between gamepad face buttons and a TV-remote select-ring + arrows based on the last-used input. - Wake-on-LAN: the fire-and-forget send is upgraded to wait-until-up (WakeController/WakeOverlay: resend + mDNS poll, 90s timeout, cancel/retry, fingerprint-matched so a host that cold-boots onto a new DHCP IP still connects), plus host edit (touch dialog + console form) with an auto-filled MAC. - Android TV: brand banner (android:banner), density-aware console scaling, D-pad/ remote nav (Up = Settings, Down or the pad Select button = host Options), emergency stream-exit chord, and 120Hz console refresh. - Touch UI: settings split into subpages with a tablet NavigationRail, axis-aware tab animation (horizontal on phones, vertical on the tablet rail), animated settings navigation, and a licenses screen with a back button + the real workspace version (read from Cargo.toml). - Vector Lock/controller icons (no emoji); bundled Geist font. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
fc1e8a8a32 |
test(mgmt): display_settings_surface stays read-only (gaming-rig now accepted)
The old `..._and_forever_rejected` asserted a 400 for keep_alive=forever; now that it's accepted, that PUT succeeded and WROTE gaming-rig into the process-global prefs, racing other tests. Rewrite read-only: assert the surface (5 presets, effective, enforced axes) and read gaming-rig=forever off the preset list — no write. Acceptance is covered on-glass (.116) + the pure policy tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
69f4c987f6 |
feat(tray): surface kept virtual displays in the tray tooltip
Stage 8 polish. `GET /api/v1/local/summary` (the tray's loopback-only unauthenticated status
source) gains `kept_displays` — the count of lingering/pinned virtual displays (held with no live
session), over the already-validated `registry::snapshot()`. The tray shows it in the idle tooltip
("idle · 1 display kept"), so a user knows a display — and, under exclusive topology, their physical
monitors — is being held (e.g. a gaming-rig `forever` pin). Release stays via the console: a
state-changing release can't be an unauthenticated endpoint, and the non-elevated Windows tray
can't read the SYSTEM-DACL'd mgmt token, so a tray release button isn't cleanly cross-platform.
`#[serde(default)]` on the tray side keeps it compatible with an older host. Tray tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
468a60c88a |
docs(display-management): Stage 8 consolidation — docs page, README, CLAUDE.md, host.env
Bring the user-facing + project docs in line with the shipped, on-glass-validated state (Stages 0-5 §6A + keep-alive hardening + gaming-rig) ahead of a merge decision: - docs-site/virtual-displays.md: drop the now-false "stored but not yet enforced / following release" caveats — conflict handling, per-client identity + KDE scaling round-trip, and §6A multi-monitor layout are all live; gaming-rig/forever ships (freed via Release); document the reconnect-always-resumes + deliberate-quit-skips-linger behavior and the PUNKTFUNK_IDLE_TIMEOUT_MS knob. KDE persistent scaling → ✅ today (validated); Windows primary → shipped; Sway exclusive stays "following release". - README: a "displays you configure, not just create" differentiator bullet. - CLAUDE.md: the display-management invariant now reflects Stages 0-5 shipped (all axes enforced, forever/Pinned, hardened reconnect) instead of "Stage 0 shipped". - host.env.example: document PUNKTFUNK_IDLE_TIMEOUT_MS + that display policy lives in the console. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
fad1e01408 |
docs(display-management): keep_alive=forever (gaming-rig) shipped
§5.1 + §7 matrix: Windows `Pinned` is shipped (
|
||
|
|
04a397be84 |
fix(vdisplay/windows): drop an unused mut in isolate-retry (clippy -D warnings)
`let (mut paths, mut modes)` — `modes` is only read (`modes.as_slice()`), never mutated. A
pre-existing unused_mut (from
|
||
|
|
ccbd7e8880 |
feat(vdisplay): ship keep_alive=forever (gaming-rig) — Windows MgrState::Pinned
Completes the last §6A-era preset. The Linux registry already resolved forever→Pinned (pure
lifecycle machine); the blockers were the Windows manager, the mgmt reject, and the console tag:
- Windows manager: new `MgrState::Pinned { mon }` — the last-released monitor under keep_alive=forever
is kept indefinitely (like Lingering but the linger timer never fires). A reconnect preempts +
recreates it (same as Lingering — a reused IddCx swap-chain is dead), snapshot reports "pinned",
and `force_release` (POST /display/release, the §8 escape hatch) frees a pinned monitor. release()
branches on the new `keep_alive_forever()`; all MgrState matches made exhaustive over Pinned.
- mgmt PUT /display/settings: stop rejecting keep_alive=forever (now honored on both platforms with a
release path). OpenAPI regenerated.
- web: un-disable the gaming-rig preset (DISABLED_PRESETS now empty) — one-click applies.
Linux paths + web/tsc/openapi green; 47 vdisplay tests pass. The Windows manager.rs is #[cfg(windows)]
(not compilable on the Linux dev box) — build-verified + on-glass validation on .173 to follow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
a0546b36b6 |
docs(display-management): record Stage 5 §6A on-glass validation + keep-alive hardening
Honesty pass after the 2026-07-05 on-glass session — the plan now reflects what was actually
validated, no more/no less:
- Stage 5 (§6A): HOST-SIDE → DONE + on-glass validated (KWin .116 + Mutter .21): group model,
positions, identity keying, group-aware exclusive/extend coexistence, 2 concurrent Mutter
RecordVirtual monitors. Remaining is hardware-gated residuals ONLY (per-group physical-restore
EFFECT needs a monitor-attached box — headless reports also_disabled=[]; wlroots exclusive;
Mutter APPLY_TEMPORARY revert).
- Stage 3: the KDE set-scaling ROUND-TRIP is now proven live (150%/125% → disconnect → reconnect
→ reapplied, kwinoutputconfig.json) — moved from Deferred to Validated. Closes the Stage-3 gate.
- §5.1: the explicit-quit bypass (
|
||
|
|
b71dc94bb2 |
test(probe): --seconds stream cap + flush the QUIC close before exit
Two probe test-infra fixes needed to validate the keep-alive hardening (
|
||
|
|
c2bc72a8e9 |
fix(packaging): correct CachyOS firewall to ufw + ship ufw openers + web-console opener
apple / swift (push) Successful in 1m11s
android / android (push) Successful in 4m1s
apple / screenshots (push) Successful in 4m29s
arch / build-publish (push) Successful in 5m52s
ci / web (push) Successful in 1m16s
ci / docs-site (push) Successful in 1m11s
ci / rust (push) Successful in 4m54s
deb / build-publish (push) Successful in 3m0s
decky / build-publish (push) Successful in 24s
ci / bench (push) Successful in 4m44s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 32s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m50s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m30s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 53s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m18s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m14s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m5s
docker / deploy-docs (push) Successful in 22s
CachyOS ships ufw enabled by default (firewalld is not installed) — verified live on the .21 box — but the docs and shipped firewall openers claimed "CachyOS enables firewalld by default". Correct that everywhere and ship a ufw application profile (the one-liner analogue of the firewalld service files): - packaging/linux/punktfunk.ufw (new): [punktfunk-native], [punktfunk-gamestream], [punktfunk-web] profiles, installed to /etc/ufw/applications.d/punktfunk by the Arch (CachyOS) and .deb host packages. `sudo ufw allow punktfunk-native`. - packaging/linux/punktfunk-web.xml (new): firewalld service for the optional web console (TCP 47992), installed by the host package on arch/deb/rpm. Neither the native nor gamestream opener covered 47992, so a firewalld/ufw host that enabled punktfunk-web could not reach the console over the LAN. - Fix the "CachyOS enables firewalld" claim in arch.md, arch/README.md, debian/README.md, both firewalld service .xml comments, and the pacman scriptlet; firewalld now attributed to the spins that use it (EndeavourOS, Fedora/RHEL). - Docs present both one-liners (ufw + firewalld) whichever firewall you run, plus a console-opener step; postinst/scriptlet hints detect ufw as well as firewalld. The native data plane stays hole-punched (ephemeral UDP, no fixed port) — its openers correctly open only 9777/udp + mDNS; the stale "open a UDP range" note is replaced with the accurate outbound-UDP explanation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b53710da1a |
feat(vdisplay): harden keep-alive reconnect — same-client preempt, quit-skips-linger, configurable idle
On-glass testing (Test 2, KWin .116) surfaced that a reconnect within the QUIC idle-timeout window (~8s) lands on a fresh SECOND display instead of reusing the kept one: the old session was still Active (not yet Lingering), so the registry's keep-alive reuse (which only matches Lingering) skipped it and the old session kept streaming to nobody. Three fixes: #3 Same-client reconnect preempt (the real fix): admission::preempt_same_identity() lists a reconnecting client's OWN still-live session(s) (same cert fingerprint); serve_session signals their stop + waits the release grace BEFORE acquiring, so the zombie tears down → its display lingers → the reconnect REUSES it instead of making a second. Implements the "preempts downstream" the admission docs already promised. Independent of the mode_conflict policy; the pure core (same_identity_stops) is unit-tested. #2 Deliberate quit skips linger: a client that deliberately disconnects closes the QUIC connection with QUIT_CLOSE_CODE (0x51, shared in core::quic); the host reads the ApplicationClosed reason and tears the display down immediately (registry release() gained force_immediate → Linger::Immediate; multi-session-safe via the pure lifecycle machine), while a bare disconnect still lingers for reconnect. Threaded via a session quit flag → the DisplayLease. NativeClient::disconnect_quit() + punktfunk-probe --quit drive it; GameStream (Quit App / h_cancel) is a documented follow-up. #1 Configurable disconnect-detection latency: the QUIC control-connection idle timeout (stream_transport, 8s default) is host-tunable via --idle-timeout-ms / PUNKTFUNK_IDLE_TIMEOUT_MS, clamped >=1s with a keep-alive that scales to it so a live session never false-closes. Default unchanged (8s stays load-bearing for the Windows IDD-push reconnect flow). Workspace check + 63 core / 215 host / 47 vdisplay tests green; clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c1acfe8b85 |
fix(web): preset cards use the design-system animated Card (motion + material)
The preset options were raw <button>s — flat, no motion/material — unlike the rest of the console. They now render as the `interactive` AnimatedCard (motion hover + specular material, consistent with every other card), keyboard-accessible (role=button + Enter/ Space), with a 2px primary ring for the active one and a proper disabled state for gaming-rig. web tsc + vite build + biome-lint green; deployed on .21. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2e43fcc27c |
fix(web): unify display-field spacing (shared Field) + clearer layout help
- Every option in the custom form now renders through one `Field` wrapper (label → control → help at a consistent `space-y-3`), so the label→input gap is roomier and identical across keep-alive, the button groups, and max-displays — the first field no longer spaces differently from the rest. - Reworded the multi-monitor layout help: it now says Auto is side-by-side and Manual gives a per-display X/Y editor "in the Live displays section below once two or more are streaming" — instead of pointing at an "arrangement table" that isn't visible until clients connect. web tsc + vite build + biome-lint green; deployed on .21. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2aa7ac8c7e |
fix(web): explicit keep-alive Off/Keep toggle + roomier custom display form
Two UX fixes on the Virtual displays Configuration card: - Keep-alive is no longer implicitly "on" by typing in the seconds field. It's an explicit two-button toggle — **Off** (tear down at disconnect) vs. **Keep for** [N] seconds — and the seconds input only appears when "Keep for" is selected. The duration is remembered across toggles, and the help text explains both modes. - Opened up the cramped custom form: the fields container is `space-y-6` with more padding (`p-5`, rounded-lg), each option group is `space-y-2.5`, and the Save button sits below a divider — so it reads as sections with room instead of a pressed stack. web tsc + vite build + biome-lint green; deployed on .21. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |